iOS開發(fā)——Swift 4.0 + Xcode9 適配小結(jié)

OC-Swift.jpeg

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)是最新的版本:


Swift版本

當(dāng)前環(huán)境

  • Mac OS 10.13.1
  • XCode 9.1
  • 當(dāng)前Swift版本 4.0

升級(jí)版本方式

更新Swift版本
  • 然后勾選需要轉(zhuǎn)換的 target (pod 引用不用勾選),Next
  • 然后選擇轉(zhuǎn)換選項(xiàng),Next
  • 這兩個(gè)選項(xiàng)是關(guān)于 swift 的 @objc 推斷特性的,如果使用了 swift4.0 顯式的 @objc 屬性,能減少整體代碼的大小。此時(shí)我們選 Minimize Inference(recommend)
updateSwiftVersinTwo.png
  • 在編譯器隱式推斷的任何地方向代碼添加一個(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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容