迁移到 Swift 5
Xcode 10.2 配备了 Swift 迁移工具,可帮助您将项目迁移到 Swift 5。
有关先前版本的迁移指南,请参阅迁移到 Swift 4.2。
迁移前准备
确保您要迁移的项目在 Swift 4 或 Swift 4.2 模式下成功构建,并且所有测试均通过。您可能需要先解决由于编译器更改而导致的错误。
强烈建议在源代码控制下管理您的项目。这将使您可以轻松查看通过迁移助手应用的更改,并在需要时放弃它们并重新尝试迁移。
您可以根据项目的实际情况,决定何时以及是否在每个目标的基础上进行迁移。虽然强烈建议迁移到 Swift 5,但这并非一个非此即彼的过程,因为 Swift 4、4.2 和 5 目标可以共存并链接在一起。
迁移助手会执行迁移构建以收集更改,使用您选择的 scheme,因此将处理 scheme 中包含的目标。要查看和修改 scheme 中包含的内容,请调用Edit Scheme… 表单,并从左侧列中选择 Build 选项卡,并确保包含所有目标及其单元测试。
如果您的项目依赖于 Carthage 或 CocoaPods 提供的其他开源项目,请查阅使用 Carthage/CocoaPods 项目部分。
Swift 迁移助手
当您首次使用 Xcode 10.2 打开项目时,您将在 Issue Navigator 中看到一个迁移机会项:单击它以激活一个表单,询问您是否要迁移。您可以稍后提醒或从菜单 Edit -> Convert -> To Current Swift Syntax… 手动调用迁移工具。
您将看到要迁移的目标列表。不包含任何 Swift 代码的目标将不会被选中。
单击Next 将会弹出 Generate Preview 表单,助手将启动迁移构建以获取源代码更改。完成后,您将看到单击“Save”后将应用的所有更改。这还将更改已迁移目标的 Swift Language Version 构建设置为 Swift 5。
处理目标时可能出现问题,这将对迁移过程产生负面影响。切换到 Report Navigator 并选择添加的 Convert 条目;这是转换构建日志。检查日志中可能出现的错误。
如果您看到有关无法对目标进行代码签名的错误,请尝试从目标的构建设置中禁用代码签名。如果您看到其他错误,请提交错误报告并包含详细信息。强烈建议您尽可能附加一个说明错误迁移的项目。
Swift 5 迁移更改概览
Swift 5 对使用 4.2 版本编译的代码的影响极小。以下是您在自己的代码中可能遇到的情况
编译器
- 编译器错误
add () to forward @autoclosure parameter
,并提供修复建议,在正确转发来自@autoclosure
参数的参数函数到标记为@autoclosure
的函数参数本身时,添加()
(形成调用)。此更改是为了解决 SR-5719 而进行的。- 迁移工具会自动应用此修复建议。
- 由于以下原因导致的类型可空性不匹配错误:SE-0230 展平嵌套可选类型
- 迁移工具将进行本地更改,以包装
try?
表达式并添加强制类型转换,以保留 Swift 4.2 版本中的类型,以便代码仍然可以编译。但是,此更改并非理想,并且违背了该提案的目的,该提案旨在消除处理 Swift 4.2 中try?
生成的嵌套可选类型的需求。建议删除强制类型转换,并在函数体中,甚至在函数签名本身中进行必要的手动更改(如果需要)。此类更改对于迁移工具来说过于侵入性,无法自动执行。
- 迁移工具将进行本地更改,以包装
- 编译器警告
switch must be exhaustive
,由于 SE-0192。- 在 Swift 5 模式下,对 Objective-C 中声明或来自系统框架的枚举的 switch 语句,需要处理“未知情况”,即未来可能添加的情况,或者可能在 Objective-C 实现文件中“私有”定义的情况。(形式上,Objective-C 允许在枚举中存储任何值,只要它适合底层类型即可。)这些“未知情况”可以使用新的
@unknown
default case 来处理,如果 switch 语句中省略了任何已知情况,它仍然会提供警告。它们也可以使用普通的 default 来处理。 - 如果您在 Objective-C 中定义了自己的枚举,并且您不需要客户端处理未知情况,则可以使用
NS_CLOSED_ENUM
宏而不是NS_ENUM
。Swift 编译器将识别这一点,并且不需要 switch 语句具有 default case。 - 在 Swift 4 和 4.2 模式下,仍然可以使用
@unknown
default。如果省略它并且将未知值传递到 switch 语句中,则程序将在运行时陷入陷阱(与 Xcode 10.1 中的行为相同)。
- 在 Swift 5 模式下,对 Objective-C 中声明或来自系统框架的枚举的 switch 语句,需要处理“未知情况”,即未来可能添加的情况,或者可能在 Objective-C 实现文件中“私有”定义的情况。(形式上,Objective-C 允许在枚举中存储任何值,只要它适合底层类型即可。)这些“未知情况”可以使用新的
Swift 标准库
- 编译器警告
'index(of:)' is deprecated: renamed to 'firstIndex(of:)'
和'index(where:)' is deprecated: renamed to 'firstIndex(where:)
- 迁移工具会执行必要的更改。
SDK
SDK 在 4.2 和 5 模式之间的源兼容性更改非常少,并且这些更改对于提高 API 的正确性是必要的。
- AppKit 中的一些 API 更改了它们的类型以返回
Any
或AnyObject
而不是NSBindingSelectionMarker
。 - AVFoundation、CloudKit 和 GameKit 具有一些属性,这些属性的返回类型变为可空
- 迁移工具将向这些属性的引用添加
!
,以保留 Swift 4.2 版本中的现有行为并保持代码编译。
- 迁移工具将向这些属性的引用添加
从 Swift 4 迁移
如果您要从 Swift 4 代码迁移,另请参阅去年从迁移到 Swift 4.2的迁移工具中的迁移更改概览。
迁移后
虽然迁移工具会为您处理许多机械更改,但您可能需要进行更多手动更改,才能在应用迁移工具更改后构建项目。
即使编译正常,迁移工具提供的代码也可能不是理想的。请使用您的最佳判断力,并检查更改是否适合您的项目。
使用 Carthage/CocoaPods 项目
以下是在使用 Swift Package Manager、Carthage 或 CocoaPods 等软件包管理器迁移具有外部依赖项的项目时需要考虑的一些要点。
- 建议使用源代码依赖项而不是二进制 Swift 模块,因为不同 Xcode 版本生成的模块彼此不兼容。或者确保获取使用 Xcode 10.2 构建的分发包。
- 确保您的源代码依赖项以及您自己的目标在 Swift 4/4.2 模式下成功构建。
- 如果您已设置框架搜索路径以查找 Carthage 构建文件夹内的二进制 Swift 模块,请删除搜索路径或清理构建文件夹,以确保您仅使用从 Xcode 工作区构建的 Swift 模块。
- 只要您的源代码依赖项可以在 Swift 4/4.2 模式下构建,就没有必要迁移它们。
其他
- 如果您的项目中有多个涵盖不同目标的 scheme,您只会收到通知,提示您需要迁移其中一个 scheme。您需要手动选择新的 scheme,然后运行 Edit -> Convert -> To Current Swift Syntax 以迁移其余 scheme。或者,您可以创建一个包含项目所有目标的 scheme,并在运行迁移助手之前选择它。