如何将你的 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 转载请注明原做者及以上信息。

相关文章
相关标签/搜索