Swift 5-期待已久的发行版,其中包含数十项改进和修复。 但是,发布Swift 5.0的主要目标是实现ABI稳定性。 在本文中,您将学习什么是ABI,以及将为iOS / macOS开发人员提供什么稳定的ABI。 我们还将分析Swift 5的几个新功能。

ABI稳定性
ABI是二进制应用程序接口。 可以将ABI视为一组规则,这些规则允许链接程序组合已编译的组件模块。
因此,以下在ABI中进行了描述。
- 从不同的模块(包括系统模块)调用代码的方式。
- 用于传递参数并从函数获取返回值的格式。
- RAM数据布局算法。
- ARC的内存管理。
- 类型系统,泛型。
Swift 5与稳定的ABI一起为应用程序提供二进制兼容性。 iOS / macOS应用程序的二进制兼容性意味着已编译的应用程序在运行时将与该语言的早期或更高版本编译的系统库兼容。 例如,使用Swift 5.0编译的应用程序将与使用Swift 5.1或Swift 6.0编译的标准库兼容。
从iOS 12.2和macOS 10.14.4开始,Apple的操作系统将包含运行swift应用程序所需的一切。 这意味着用Swift 5及更高版本编写的应用程序将不包含运行时和标准语言库。 因此,用Swift 5编写的应用程序的重量将减少约3-10兆字节。
重要的是要注意,除了ABI稳定性外,还有模块稳定性。 如果ABI稳定性允许在运行时组合不同版本的swift,则模块稳定性负责如何编译用该语言的不同版本编写的二进制框架。 模块稳定性将出现在Swift 5.1中。 然后,开发人员将不仅可以以开源形式分发其框架,还可以以编译形式分发其框架。
ABI稳定性的优点。
- 应用程序将减轻重量。
- 加快启动和应用程序性能。
- 从理论上讲,Apple可以完全在Swift上编写新框架。
缺点ABI稳定性。
开发人员将不得不考虑在标准库的旧版本中缺少任何新功能。 例如,如果Swift 13内置于iOS 13中,并且在标准库中具有一些新的类/函数,则在iOS 12.2中的支持下,开发人员将无法使用它们。 (您需要以与现在对Foundation,UIKit和其他平台库相同的方式插入#available(...)检查)。
标准库中的结果类型
标准库提供了一种方便的方式来传输和处理异步API中的错误。 如果由于某些原因通过try / catch处理的标准错误不适合我们,您也可以使用此类型。
Result类型通过枚举实现,有两种情况:成功和失败:
public enum Result<Success, Failure> where Failure: Error { case success(Success) case failure(Failure) ... }
实际上,这种方法对于Swift开发人员而言并不陌生。 从Swift的第一个版本开始,许多开发人员就使用了类似的方法。 但是现在,当结果出现在标准库中时,这将简化与外部库中的代码的交互。
使用文章下载服务的示例:
struct Article { let title: String } class ArticleService { func fetchArticle(id: Int64, completion: @escaping (Result<Article, Error>) -> Void) {
这是处理结果的示例。 由于Result只是一个枚举,因此我们可以使用开关来处理其所有状态:
articleService.fetchArticle(id: 42) { result in switch result { case .success(let article): print("Success: \(article)") case .failure(let error): print("Failure: \(error)") } }
原始字符串
在Swift 5中,他们添加了所谓的原始字符串,其中的引号和反斜杠被完全解释为字符,并且在文字中使用它们时,无需使用转义字符。 要为这样的字符串编写文字,必须将#字符添加到边缘的双引号中。
使用引号的示例:
编写正则表达式时,此功能特别有用:
要在反斜杠后插入行,请添加#字符:
您可以在这句话中阅读更多内容。
更新了线插值
使用字符串插值,我们可以将变量的值或表达式的结果添加到字符串文字中。 从语言的第5版开始,可以扩展将表达式添加到最后一行的方式。
通常,只需为DefaultStringInterpolation结构编写一个扩展,然后添加一个名为appendInterpolation的方法。 例如,如果我们要以格式将价格添加到字符串中:
extension DefaultStringInterpolation { mutating func appendInterpolation(price: Decimal) { let formatter = NumberFormatter() formatter.numberStyle = .currency if let string = formatter.string(from: price as NSDecimalNumber) { appendLiteral(string) } else { appendLiteral(price.description) } } } print("Price of item: \(price: 9.99)")
重要的是要注意,实际上,使用编译器在字符串中的构造(价格:9.99)已转换为对appendInterpolation(价格:Decimal)方法的调用。
同样,在appendInterpolation方法中,我们可以添加无限数量的带名称和不带名称的参数,无论是否包含默认值。
您可以在这句话中阅读更多内容。
检查数字的多重性
检查多重性isMultiple(of :)的方法已添加到标准库中的数字类型。 是的,我们仍然可以使用运算符来取除%的余数。 但似乎isMultiple(:)看起来更直观。
let interger = 42 if interger.isMultiple(of: 3) { print(" ") } else { print(" ") }
词典中的CompactMapValues方法
compactMapValues方法允许您转换字典值,并在转换本身返回nil时过滤它们。
例如,将字符串键映射到URL类型:
let dict = [ "site": "https://www.site.ru/path/to/web/site/page", "other site": "invalid url" ] let mappedDict: [String: URL] = dict.compactMapValues { URL(string: $0) } print(mappedDict)
由于字符串不是有效的URL,因此在映射后删除了第二个键/值对。
尝试改变行为?
在Swift 4.2中使用try构造? 您可以轻松获得具有多个嵌套级别的可选类型。 在大多数情况下,这不是开发人员所期望的。 因此,在Swift 5中尝试吗? 行为类似于c可选链接。 也就是说,结合尝试吗? 如果使用可选的链接或可选的强制转换,则表达式的结果将是具有一层嵌套的可选的结果。
试试例子吗? 与as?:
试试例子吗? 连同可选的object方法:
您可以在这句话中阅读更多内容。
@DynamicCallable属性
新的@dynamicCallable属性使您可以将类型标记为“可调用”。 这意味着我们可以将类型称为常规方法。
如果将类型标记为@dynamicCallable,则必须实现一个(或两个)方法:
func dynamicallyCall(withArguments: <#Arguments#>) -> <#R1#> func dynamicallyCall(withKeywordArguments: <#KeywordArguments#>) -> <#R2#>
Arguments类型必须支持ExpressibleByArrayLiteral协议,KeywordArguments类型必须支持ExpressibleByDictionaryLiteral协议,并且R1和R2可以是任何类型。
例如,求和的结构。 呼叫时,您可以转移任意数量的数字并获取其总和:
@dynamicCallable struct Sum { func dynamicallyCall(withArguments args: [Int]) -> Int { return args.reduce(0, +) } } let sum = Sum() let result = sum(1, 2, 3, 4) print(result)
实际上,编译器将sum(1、2、3、4)转换为对sum.dynamicallyCall(withArguments:[1、2、3、4])的调用。 对于dynamicCall(withKeywordArguments :)方法类似。
此功能使您可以添加Swift代码与各种动态编程语言(例如Python或JavaScript)的交互。
您可以在这句话中阅读更多内容。
较少的操作员对编译器版本和语言检查指令的支持
从Swift的第5版开始,您可以在代码中检查编译器版本时使用“ less”运算符:
结论
这些并不是Swift 5中出现的所有功能和改进。总共接受了来自社区的28条建议,其中包括提高生产线性能,改进Swift软件包管理器和标准库。 更改和改进的完整列表可以在发行说明中找到。