标签:pair 泛型类 命令行 test 动态 协议 使用 access keyword
Swift 5新特性详解:ABI 稳定终于来了!
译者|薛命灯
编辑|覃云
近日,苹果开发者博客更新了一篇关于 Swift 5 的文章,带来了 Swift 5 新特性的消息,其中最受开发期待的莫过于 iOS 12.2 将带来 ABI 稳定性,这意味着基础库将植入系统中,不再包含在 App 中,应用程序的体积会更小,更多新功能请看下文。
新功能
Swift 应用程序不再包含用于 Swift 标准库和 Swift SDK(运行 iOS 12.2、watchOS 5.2 和 tvOS 12.2 的设备的构建变体)的动态链接库。因此,在使用 TestFlight 进行测试时,或者为本地开减小应用程序体积时,Swift 应用程序可以变得更小。
要查看 iOS 12.2 和 iOS 12.1(或更早版本)应用程序之间的文件大小差异,请将应用程序的部署目标设置为 iOS 12.1 或更早版本,将 scheme 设置为 Generic iOS Device,然后创建应用程序压缩包。
在构建好压缩包之后,从压缩包管理器中选择 Distribution App,然后选择 Development Distribution。确保在 App Thinning 下拉菜单中选择特定的设备,比如 iPhone XS。这个过程完成后,在新创建的文件夹中打开 App Thinning Size Report。iOS 12.2 的体积会比 iOS 12.1 或更早版本的体积小。具体的大小差异取决于应用程序使用的框架的数量。
@dynamicCallable 属性允许你调用命名的类型,就像使用简单的语法糖调用函数一样。主要的应用场景是动态语言互操作性。
例如:
@dynamicCallable struct ToyCallable {
func dynamicallyCall(withArguments: [Int]) {}
func dynamicallyCall(withKeywordArguments: KeyValuePairs<String, Int>) {}
}
let x = ToyCallable()
x(1, 2, 3)
// Desugars to `x.dynamicallyCall(withArguments: [1, 2, 3])`
x(label: 1, 2)
// Desugars to `x.dynamicallyCall(withKeywordArguments: ["label": 1, "": 2])`
现在支持标识 KeyPath(.self),一个引用其整个输入值的 WritableKeyPath(https://developer.apple.com/documentation/swift/writablekeypath?language=objc):
let id = \Int.self
var x = 2
print(x[keyPath: id]) // Prints "2"
x[keyPath: id] = 3
print(x[keyPath: id]) // Prints "3"
在 Swift 5 之前,你可以编写一个带有可变参数的枚举:
enum X {
case foo(bar: Int...)
}
?func baz() -> X {
return .foo(bar: 0, 1, 2, 3)
}
现在如果这么做会出错。相反,现在参数改成了一个数组,并且需要显式传入数组:
enum X {
case foo(bar: [Int])
}
?func baz() -> X {
return .foo(bar: [0, 1, 2, 3])
}
在 Swift 5 模式下,可以用? 和 Optional 类型表达式来扁平化生成的 Optional,而不是返回嵌套的 Optional。
如果类型 T 符合这些字面量初始化(https://developer.apple.com/documentation/swift/swift_standard_library/initialization_with_literals?language=objc)中的一个——例如 ExpressibleByIntegerLiteral——并假设 literal 是一个字面量表达式,那么 T(literal) 就创建了一个 T 类型的字面量。
例如,UInt64(0xffff_ffff_ffff_ffff) 现在是有效的,而之前它们会导致默认整型字面量类型 Int 溢出。
字符串插值的性能、清晰度和效率得到了改进。
旧的 _ExpressibleByStringInterpolation 协议被移除,如果你的代码使用了这个协议,需要更新这些代码,你可以使用 #if 在 Swift 4.2 和 Swift 5 之间条件化代码。例如:
#if compiler(<5)
extension MyType: _ExpressibleByStringInterpolation { /*...*/ }
#else
extension MyType: ExpressibleByStringInterpolation { /*...*/ }
#endif
extension Sequence {
func dropTwo() -> SubSequence {
return self.dropFirst(2)
}
}
变为:
extension Sequence {
func dropTwo() -> DropFirstSequence<Self> {
return self.dropFirst(2)
}
}
或者:
extension Collection {
func dropTwo() -> SubSequence {
return self.dropFirst(2)
}
}
$ swift package config set-mirror --package-url <original URL> --mirror-url <mirror URL>
Cross-reference to module ‘UIKit‘
... UIAccessibility
... in an extension in module ‘UIKit‘
... GuidedAccessError
包含 NS_ERROR_ENUM 枚举的其他类型也可能出现这个问题,但 UIAccessibility 是最常见的。
解决方法:使用“Swift Compiler - Code Generation”下的 Whole Module 编译模式选项重新构建,这是大多数发布配置的默认设置。
class Base {
class func factory() -> Self { /*...*/ }
}
class Derived: Base {
class override func factory() -> Derived { /*...*/ }
}
struct Foo<T> {}
extension Foo {
struct i {}
// Error: Invalid redeclaration of ‘i‘.
// (Prior to Swift 5, this didn’t produce an error.)
static var i: Int { return 0 }
}
func foo(_ fn: @autoclosure () -> Int) {}
func bar(_ fn: @autoclosure () -> Int) {
foo(fn) // Incorrect, `fn` can’t be forwarded and has to be called.
foo(fn()) // OK
}
func forceCast<U>(_ value: Any?, to type: U.Type) -> U {
return value as! U
}
let value: Any? = 42
print(forceCast(value, to: Any.self))
// Prints "Optional(42)"
// (Prior to Swift 5, this would print "42".)
print(value as! Any)
// Prints "Optional(42)"
协议现在可以将符合类型限定为给定类的子类。支持两种等效形式:
protocol MyView: UIView { /.../ }
protocol MyView where Self: UIView { /.../
Swift 4.2 接受了第二种形式,但还没有完全实现,在编译时或运行时偶尔会发生崩溃。
* 在 Swift 5 模式下,当在自己的 didSet 或 willSet observer 中设置属性时,observer 现在只在 self 上设置属性(不管是隐式的还是显式的)时才会避免被递归调用。
例如:
class Node {
var children = [Node]()
var depth: Int = 0 {
didSet {
if depth < 0 {
// Won’t recursively call didSet, because this is setting depth on self.
depth = 0
}
// Will call didSet for each of the children,
// as this isn’t setting the property on self.
// (Prior to Swift 5, this didn’t trigger property
// observers to be called again.)
for child in children {
child.depth = depth + 1
}
}
}
}
* 如果你使用 #sourceLocation 将生成文件中的行映射回源代码,那么诊断信息将显示在源文件中而不是生成文件中。
* 使用泛型类型别名作为 @objc 方法的参数或返回类型不会再生成无效的 Objective-C 标头。
英文原文:
https://developer.apple.com/documentation/xcode_release_notes/xcode_10_2_beta_release_notes/swift_5_release_notes_for_xcode_10_2_beta?language=objc
标签:pair 泛型类 命令行 test 动态 协议 使用 access keyword
原文地址:https://blog.51cto.com/15057848/2567751