
iOS開發(fā)中,我們需要根據(jù)用戶需要去適配各種各樣的版本,特別是蘋果爸爸的每一次新版本發(fā)布,作為開發(fā)者的我們永遠(yuǎn)是最先知道的,并且奮斗在最前線:
- Xcode適配
- Swift版本更新
- iPhone適配
- iOS系統(tǒng)適配
這里主要介紹一下最新版 Swift 4.0 適配,并簡(jiǎn)單的說(shuō)一下關(guān)于Xcode9特性與適配的問題
關(guān)于Swift新特性可以參考這里:Swift 4.0 新特性
前言
Xcode 9 中同時(shí)集成了 Swift 3.2 和 Swift 4。
- Swift 3.2 完全兼容 Swift 3.1,并會(huì)在過時(shí)的語(yǔ)法或函數(shù)上報(bào)告警告。
- Swift 3.2 具有 Swift 4 的一些寫法,但是性能不如 Swift 4。
- Swift 3.2 和 Swift 4 可以混合編譯,可以指定一部分模塊用 Swift 3.2 編譯,一部分用 Swift 4 編譯。
- 遷移到 Swift 4 后能獲得 Swift 4 所有的新特性,并且性能比 Swift 3.2 好。
總結(jié):
當(dāng) Xcode 正式版發(fā)布后,現(xiàn)有的 Swift 代碼可以直接升級(jí)到 Swift 3.2 而不用做任何改動(dòng),也可以后續(xù)再遷移到 Swift 4。 或者直接遷移到 Swift 4 也可以,Swift 4 相比 Swift 3 的 API 變化還是不大的,很多第三方庫(kù)都可以直接用 Swift 4 編譯。 Swift 1 到 2 和 Swift 2 到 3 的遷移的痛苦在 3 到 4 的遷移上已經(jīng)大大改善了。
適配
關(guān)于Swift 4適配中OC與Swift混編的坑比較多
查看當(dāng)前版本
我這里已經(jīng)是最新的版本:

當(dāng)前環(huán)境
- Mac OS 10.13.1
- XCode 9.1
- 當(dāng)前Swift版本 4.0
升級(jí)版本方式

- 然后勾選需要轉(zhuǎn)換的 target (pod 引用不用勾選),Next
- 然后選擇轉(zhuǎn)換選項(xiàng),Next
- 這兩個(gè)選項(xiàng)是關(guān)于 swift 的 @objc 推斷特性的,如果使用了 swift4.0 顯式的 @objc 屬性,能減少整體代碼的大小。此時(shí)我們選 Minimize Inference(recommend)

- 在編譯器隱式推斷的任何地方向代碼添加一個(gè)@objc屬性。這個(gè)選項(xiàng)不會(huì)改變你的二進(jìn)制文件的大小,因?yàn)楸籗wift 3隱式推斷在所有的地方都添加了顯式的@objc屬性。
- 根據(jù)靜態(tài)推斷,僅在需要的地方添加@objc屬性。使用此選項(xiàng)后,需要按照Completing a Swift 4 minimize inference migration來(lái)完成轉(zhuǎn)換。
- Minimize Inference(recommend)
- Match Swift 3 Behavior
升級(jí)完成后可能會(huì)運(yùn)行不起來(lái)
編譯不通過
如果項(xiàng)目中之前有class和extension,有些也給OC調(diào)用。在OC的代碼中,我們通過#import "ModuleName-Swift.h"導(dǎo)入了Swift文件。如果是Swift3.2,一切都能正常工作,但是在Swift4.0上,編譯通不過了。
如果你看了Swift 4特性的話應(yīng)該知道
swift4.0 最大的特性之一就是 @objc 修飾符的變化了,它主要處理 OC 和 swift 混編時(shí)一些方法的調(diào)用以及屬性獲取問題,swift4.0 將在 swift3.x 中一些隱式類型推斷的特性去除以后,需要我們來(lái)手動(dòng)管理 @objc 修飾符。
具體解決方案:
- 一:在OC中調(diào)用一個(gè)Swift4.0類的方法(包括實(shí)例方法、static方法、class方法),你需要:
- 在該Swift4.0類前加上修飾符@objc
- 該Swift4.0類必須繼承NSObject(否則,無(wú)法在前面加上修飾符@objc。當(dāng)然,這里指的是普通類,@objc也是可 以修飾UI開頭的一系列UIKit框架下的UI類,只是修飾了這些類,不會(huì)產(chǎn)生什么影響)
- 在需要調(diào)用的方法前加上修飾符@objc
- 二:在OC中調(diào)用一個(gè)Swift4.0擴(kuò)展的屬性(包括實(shí)例屬性、static屬性、class屬性)、方法(包括實(shí)例方法、static方法、class法),你有如下兩種選擇方式:
- 在該Swift4.0擴(kuò)展前加上修飾符@objc(這樣的話,該擴(kuò)展下的所有的屬性、方法,都可被OC調(diào)用)。
- 在需要的屬性、方法前直接加上@objc修飾,也可達(dá)到目的。
注意一點(diǎn):swift3 使用 #selector 指定的方法,只有當(dāng)方法權(quán)限為 private 時(shí)需要加 @objc 修飾符,swift4.0 都要加 @objc 修飾符 swift4.0 不再允許重載 extension 中的方法(包括instance、static、class方法)
運(yùn)行時(shí)找不到屬性
如果你有一個(gè)Swift類繼承自UIViewController,OC中調(diào)用或者操作這個(gè)類[viewController valueForKey:@"userName"]這一KVC方法去獲取這個(gè)自定義UIViewController中的userName這一屬性的屬性值。
這種方式,編譯時(shí)是無(wú)法檢查出問題的。但是在運(yùn)行時(shí),問題就來(lái)了,找不到這個(gè)屬性。因?yàn)檫@個(gè)屬性沒有暴露給OC來(lái)進(jìn)行調(diào)用。
解決方案:
- 僅需要在自定義的UIViewController類中給需要暴露給OC調(diào)用的屬性前加上@objc修飾符便可。如此一來(lái),在OC代碼中就能訪問到這個(gè)屬性。
(注意:這里可不像上面提到的extension一樣,在這個(gè)已定義的UIViewController類前面加上@objc修飾符沒有任何意義)。
編譯警告
運(yùn)行時(shí)警告會(huì)打印在控制臺(tái):
***Swift runtime:
ClassName.swift:lineInFile:columnInLine:
entrypoint -[ClassName methodName] generated by implicit @objc inference is deprecated and will be removed in Swift 4;
add explicit @objc to the declaration to emit the Objective-C entrypoint in Swift 4 and suppress this message
同樣:想要修復(fù)運(yùn)行時(shí)警告,需要添加 @objc 修飾符到對(duì)應(yīng)的方法或者符號(hào)。
運(yùn)行時(shí)警告的常見原因:
- 在 OC 中使用 SEL
- 在 swift 中使用了 perform methods
- 在 OC 中使用了 performSelector methods
- 使用了 @IBOutlet 或者 @IBAction
其他修改
NSAttributedStringKey
swift3.x
public init(string str: String, attributes attrs: [AnyHashable : Any]? = nil)
swift4.0
public init(string str: String, attributes attrs: [NSAttributedStringKey : Any]? = nil)
String
廢棄characters
swift 3
var count = string.characters.count
error
'characters' is deprecated: Please use String or Substring directly
swift 4
count = string.count
廢棄addingPercentEscapes
swift 3
var url = @"http://www.example.com?username=姓名"
url = url.addingPercentEscapes(using: String.Encoding.utf8)!
error
'addingPercentEscapes(using:)' is unavailable: Use addingPercentEncoding(withAllowedCharacters:) instead, which always uses the recommended UTF-8 encoding, and which encodes for a specific URL component or subcomponent since each URL component or subcomponent has different rules for what characters are valid.
swift 4
uri = uri.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
廢棄substring(to:)
swift 3
let index = tagText.index(tagText.startIndex, offsetBy: MPMultipleStyleListItemTagMaxLength)
// 警告:'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range upto' operator.
let b = tagText.substring(to: index)
Swift 4
let a = tagText.prefix(upTo: index) //a 的類型是 Substring,不是 String
pod 引用
添加以下內(nèi)容到 Podfile
post_install do |installer|
installer.pods_project.targets.each do |target|
if ['WTCarouselFlowLayout', 'XSLRevenue', 'OHHTTPStubs/Swift'].include? target.name
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '3.2'
end
end
end
end
系統(tǒng)方法
UITableViewDelegate 協(xié)議方法名變更,沒有錯(cuò)誤提示:
// swift3.x
func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: IndexPath) -> CGFloat
// swift4.0
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
總結(jié)
Swift3.2到Swift4.0的改變:
Swift4.0中對(duì)于擴(kuò)展的屬性(包括實(shí)例屬性、static屬性、class屬性),都只能使用get方法,不可使用set方法
Swift4.0中不再允許復(fù)寫擴(kuò)展中的方法(包括實(shí)例方法、static方法、class方法)
編譯期與運(yùn)行時(shí)警告處理,添加 @objc 修飾符到對(duì)應(yīng)的方法或者符號(hào)。
swift3使用#selector指定的方法,只有當(dāng)方法權(quán)限為private時(shí)需要加@objc修飾符,現(xiàn)在全都要加@objc修飾符
-
字體方面的一些重命名:
- NSFontAttributeName重命名為NSAttributedStringKey.font
- NSForegroundColorAttributeName重命名為NSAttributedStringKey.foregroundColor
- NSStrikethroughStyleAttributeName重命名為NSAttributedStringKey.strikethroughStyle