嗨,我叫伊利亚。 我是Tinkoff.ru的iOS开发人员。 在本文中,我将简要概述Swift 5中的主要更改。这些更改在
发行说明中进行了描述。 对于尚未熟悉自己的人,欢迎猫来!

应用程序的大小将减小!
用Swift 5编写并针对iOS 12.2,watchOS 5.2,tvOS 12.2编译的应用程序将不包含Swift标准库和Swift SDK的动态库。 这意味着应用程序的大小将减少很多。 如果您相信
此推文 ,则空项目的大小将从2.4 Mb减少到24 Kb。 对于小型应用程序,这是一个很好的结果,但是对于大型应用程序,则没有太大的区别。
@dynamicCallable( SE-0216 )
@dynamicCallable属性允许
您将对象作为函数使用。 此类对象称为功能对象或函子(可在
此处找到更多详细信息)。 功能对象使用C ++,Python,JavaScript和其他语言,而在Swift中则添加了它们以与这些语言兼容。 事实是,Swift现在可以与API C和Objective-C很好地交互,并且语言开发人员希望添加与动态语言(Python,JavaScript,Ruby和其他语言)的交互。
为了使类型成为函子,必须在其声明中添加
@dynamicCallable属性。 考虑一个可用于在数组中加数字的
Reducer结构示例:
@dynamicCallable struct Reducer { ... }
然后,您需要实现以下一种或两种方法:
func dynamicallyCall(withArguments: ExpressibleByArrayLiteral) func dynamicallyCall(withKeywordArguments: ExpressibleByDictionaryLiteral)
第一个功能允许您通过传递数组作为参数来访问对象。 第二个函数允许您访问对象,并传递与参数相同的数组,但是使用参数的名称。
例如,
Reducer结构的第一个功能的实现如下所示:
func dynamicallyCall(withArguments arguments: [Int]) -> Int { return arguments.reduce(0, +) }
然后应用如下结构:
let reducer = Reducer() let sum = reducer(1, 2, 3)
我们将使用
Comparator结构的示例来考虑第二种方法的实现,通过该示例我们可以比较两个数字:
@dynamicCallable struct Comparator { func dynamicallyCall(withKeywordArguments arguments: KeValuePairs<String, Int>) -> ComparisonResult { guard let lhs = arguments["lhs"], let rhs = arguments["rhs"], lhs != rhs else { return .orderedSame } return lhs > rhs ? .orderedDescending : .orderedAscending } }
您可以按以下方式使用此结构:
let comparator = Comparator() let comparisionResult = comparator(lhs: 1, rhs: 2)
许多人都知道,在处理枚举值时,有必要描述所有情况,并尽量不要使用默认值。 尽管此要求增加了一定的安全性,但它也有一个缺点,因为在枚举中更改值时,您需要添加其处理。 系统框架仍可能会更改其中一个枚举,但是您的应用程序尚未对此进行处理(例如,使用
LABiometryType进行了
更改 )。
Swift 5将添加
unknown属性,这将允许您在处理枚举时分离2个不同的场景:
- 对于所有未在switch中处理的情况,都应执行默认代码
- 所有案例都在switch中处理,如果添加了新案例,那么您需要在默认情况下使用代码
让我们看一个例子:
enum HTTPMethod { case post, get, put }
摆脱double可选,因为使用try调用了函数? ( SE-0230 )
当然有很多人遇到这样的事实,即在调用throwable函数时,它使用
try方法返回
Optional ? ,结果是一个包装在两个
Optional中的类型。 这不是很方便,因此在Swift 5中,请
尝试吗? 在这种情况下,将返回仅包装在一个
Optional中的类型。
这是Swift 5之前的样子:
let result = try? optionalObject?.foo()
因此它将在Swift 5中:
let result = try? optionalObject?.foo()
要检查一个数字与另一个数字的多重性,可以使用
isMultiple(:)函数,而不是除数的余数(%):
所做的更改很小,但是使代码更清晰,并简化了代码搜索。
对带有条件的序列中的元素数进行计数( SE-0220 )
在Swift 5中,Sequence类型将添加
count(其中:(Element)-> Bool)-> Int方法,该方法允许您一次计算满足给定条件的序列中的元素数。 在此之前,我必须结合使用
filter和
count 。 该方法将节省在
filter方法中创建新数组时分配的内存。
一个例子:
let countOfZeroes = [0, 1, 2, 0, 4].count(where: { $0 == 0 })
词典中的CompactMapValues方法( SE-0218 )
此方法将
Array中的 compactMap和
Dictionary中的 mapValues组合在一起。 调用此方法的结果是,创建了一个具有转换值的字典,其中没有等于
nil的值。
一个例子:
let dictionary = ["a": "1", "b": "2", "c": "Number"] let resultDictionary = dictionary.compactMapValues { Int($0) }
新增了写引号和反斜杠用作常规字符而不是特殊字符的行的功能。 为此,请在行的开头和结尾添加#字符。
一个例子:
let string1 = #" " ""# let string2 = #" \ "#
如果要在创建行时插入变量,则在反斜杠后需要添加#号:
let string = #" \#(variable)"#
如果该行带有#号,则需要在该行的开头和结尾添加两个##符号:
let string = ##" #"##
序列协议不再包含关联的类型SubSequence( SE-0234 )
SubSequence的关联类型已从
Sequence协议移至
Collection, 现在 Sequence中所有返回
SubSequence的方法
都返回特定类型。 例如,
后缀方法现在返回一个
Array 。 这是受此更改影响的方法的完整列表:
extension Sequence { public func dropFirst(_ k: Int = 1) -> DropFirstSequence<Self> public func dropLast(_ k: Int = 1) -> [Element] public func suffix(_ maxLength: Int) -> [Element] public func prefix(_ maxLength: Int) -> PrefixSequence<Self> public func drop(while predicate: (Element) throws -> Bool) rethrows -> DropWhileSequence<Self> public func prefix(while predicate: (Element) throws -> Bool) rethrows -> [Element] public func split( maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true, whereSeparator isSeparator: (Element) throws -> Bool ) rethrows -> [ArraySlice<Element>] }
现在,使用这些方法将变得更加容易。
协议限制
协议现在以实现该协议的类的形式支持该限制。 换句话说,您现在可以指示协议只能由特定的类实现。 例如:
protocol Viewable: UIView {} protocol Viewable where Self: UIView {}
Swift 4.2支持第二个录制选项,但可能会导致编译错误或运行时。 在Swift 5中,不会发生此错误。
结论
这不是Swift 5中更改的完整列表;此处仅收集主要更改。 通常,所呈现的变化是积极的,并使语言更易于理解和灵活。 最主要的是,“转换为当前的Swift语法”应该很轻松。
就这样,谢谢您的阅读。