如何將你的 CocoaPods 庫升級到 Swift 4

零. 前言

Swift 版本升級嘛,你們應該都很熟練了,菜單 -> Edit -> Convert -> To Current Swift Syntax...,而後巴拉巴拉一頓操做。emmmn,抱歉,編譯過了也不必定能正常使用。git

此次 Swift 3 到 Swift 4 的更新和以前的大版本更新相比,已經平滑了不少,相較以前的動輒幾百上千個 error,如今用 Xcode 進行 Convert 以後基本上只須要進行少許人工修正便可,不過仍然有一些點須要注意,本文將會對一些常見的坑或者注意點以及解決方法進行討論。github

本文以 EFCountingLabel 的 1.0.3 版本和 Xcode 9.0 爲例,主要關於原有的 Swift 3 的 CocoaPods 庫到 Swift 4 的升級,仍處於 Swift 2 階段的同窗可暫時忽略本文。swift

一. 升級流程

1. 查看當前版本

首先用 Xcode 打開工程,看一下當前工程設置的 Swift 版本,若是太低的話可能沒法直接 Convert,選中須要轉換的 target 搜索 swift_ver 便可,如圖所示:bash

這裏 EFCountingLabel 的 Swift 版本爲 3.2,若是是 2.x 的話須要本身想辦法先轉換成 Swift 3.x...函數

2. Xcode 代碼轉換

接下來,就是利用 Xcode 實現代碼轉換了,菜單 -> Edit -> Convert -> To Current Swift Syntax...,而後選中須要轉換的 target,點擊 Next 按鈕便可:post

3. 選擇轉換模式

而後會出現一個轉換模式選項,有 Minimize Inference(recommended)Match Swift 3 Behavior 兩個選擇,蘋果推薦的是第一個選項:測試

蘋果官方文檔對這兩個選項的描述以下,大意是:若是選第一個選項,會僅在必要的時候爲方法或屬性添加 @objc 標誌,不過大部分工做須要用戶(也就是你)手動完成,好處是能減小最終生成的二進制文件的大小;若是選擇第二個選項,則會按 Swift 3 的方式給全部的地方直接添加 @objc 標誌(關於 @objc 標誌的介紹你們能夠參考 Swift 翻譯組的這篇文章),缺點就是不會對生成的二進制文件大小進行優化(也就是跟 Swift 3 同樣):優化

這裏咱們分幾種狀況:spa

  1. 若是你的 Swift 庫不打算支持 OC 調用的話,選 Minimize Inference(recommended),檢查而且保存自動轉換結果便可,而後能夠直接跳到下一小節,請忽略下面這一大段;
  2. 若是你的 Swift 庫打算支持 OC 調用,可是開發時間緊迫暫時沒時間仔細設置 @objc 標誌或者對這一點二進制文件體積的縮減並非十分在乎的話,選 Match Swift 3 Behavior,檢查而且保存自動轉換結果便可,而後能夠直接跳到下一小節,請忽略下面這一大段;
  3. 若是你的 Swift 庫打算支持 OC 調用,而且打算用推薦的方式進行優化的話,選 Minimize Inference(recommended),保存更改,而後按下面的操做去作:
1. 編譯工程;
2. 修正那些提示你須要添加 @objc 標誌的警告(請務必修正,否則即便編譯能過運行時也可能會出問題);
3. 修正 Xcode 提示的不須要添加 @objc 標誌的代碼,持續構建和測試你的代碼,直到沒有任何警告出現;
4. 打開工程設置;
5. 選中 target,搜索 `@objc` 找到 `Swift 3 @objc Inference` 選項,設爲 `Default`。
複製代碼

唔,以上這段大概是原文翻譯過來的了,官方文檔原文如圖所示:翻譯

須要注意的是,由於咱們這裏針對的並非完整的 iOS 項目,而是 CocoaPods 庫,若是你的 OC Demo 沒有調用庫中須要暴露的功能(或者乾脆沒有 OC Demo),辣麼編譯器可能徹底不會給你任何提示而是直接經過編譯了,直到你某一天在一個 OC 工程中引入這個庫纔會發現並不能調用到某些方法或獲取某些屬性。

因此其實麻煩之處在於,編譯器並不會給你任何提示,由於編譯器也不知道哪些類 / 屬性 / 方法須要暴露,哪些須要被優化掉,須要開發人員本身決定並手動添加對應的 @objc 標誌,總結起來的話有如下幾點:

  1. 須要在 OC 中調用一個 Swift 4 的類,須要讓這個類繼承 NSObject 而且在這個類前加上 @objc 標誌;
  2. 須要在 OC 中調用一個 Swift 4 類的方法,須要在方法前加上 @objc 標誌(這裏有一個坑,若是是普通的函數調用還好,至少編譯器會報錯,若是是用 #selector 的方式調用的話,能過編譯而且在運行時直接找不到對應方法而閃退,建議升完 Swift 4 檢查一下全部的 #selector 調用);
  3. 須要在 OC 中訪問一個 Swift 4 類的某個屬性,須要在屬性前加上 @objc 標誌(同上,若是是普通屬性訪問的話編譯器會報錯,可是 KVC 的話會在運行時找不到屬性而崩潰,記得檢查...);
  4. 須要在 OC 中訪問一個 Swift 4 類的擴展,只要在擴展前加上 @objc 標誌,該擴展的屬性和方法就都能被調用了。

4. 更新 Xcode 設置

  1. 以下圖所示,根據 Xcode 提示將工程設置進行更新,點擊 Warning 後單擊 Perform Changes 按鈕便可;

  1. 檢查設置,將全部 target 的 Swift 3 @objc Inference 設置(若是有的話)改成 Default,以前改過的話就不用改了;
  2. 搜索 swift_ver,能夠看到當前的 Swift Language Version 已是 Swift 4 了。

剩下少許方法名變更之類的更新你們能夠根據提示自行修改,到這裏基本就完成了升級過程,不過先別急,接下來咱們看注意事項。

二. 注意事項

如下狀況必需要給對應的屬性或方法添加 @objc 標誌(固然,他們所在的類確定也須要添加 @objc 標誌),不論是經過 OC 仍是 Swift 調用:

  1. 使用 @selector()#selector() 方式調用的函數;
  2. 使用 KVC 進行訪問的屬性;
  3. 使用 IBOutlet 或者 IBAction 和 StoryBoard 綁定的函數或屬性。

這些有部分在官方文檔中也有說起:

三. 一些問題

  1. 同一工程的 Pods 庫是否能夠既有 Swift 3 的也有 Swift 4 的?

Swift 的版本控制粒度在 framework 層面,也就是說同一個工程中不一樣的 framework 能夠是按不一樣版本的 Swift 進行編譯的,因此並不須要等待項目依賴的全部 Pods 庫都支持 Swift 4 後再更新,徹底能夠將已經升級 Swift 4 的庫先用起來。

  1. Swift 3 @objc Inference 選項是幹啥的?

在 Swift 4 以前,編譯器對 Objective-C 自動提供了一些 Swift 聲明。例如,編譯器會爲 NSObject 子類的全部方法建立 Objective-C 入口點,該機制稱爲 @objc 推斷(@objc Inference)。

在 Swift 4 中,這種自動的 @objc 推斷已被廢棄,由於生成全部這些 Objective-C 入口點有代價,會增大最終的二進制文件體積。當 Swift 3 @objc Inference 設置爲 On 時,它會按照 Swift 4 以前的模式運行,不進行優化,也就是隱式爲咱們編寫的全部 Swift 代碼提供 OC 入口。

可是,當設置爲 On 時 Xcode 會報一個警告,建議修復這個警告,並將設置切換到 Default。新的 Swift 項目的默認爲「Default」。能夠理解爲該項設置爲 On 時和上文代碼轉換時選擇 Match Swift 3 Behavior 選項效果相似。

四. 沒了

升級完請務必跑一遍總體測試流程,暗坑無數,以防萬一,祝你們線上穩定。


若有任何知識產權、版權問題或理論錯誤,還請指正。 https://juejin.im/post/5a32180551882554b83790ca 轉載請註明原做者及以上信息。

相關文章
相關標籤/搜索