近日,苹果开发者博客更新了一篇关于Swift 5的文章,带来了Swift 5新特性的消息,其中最受开发期待的莫过于iOS 12.2将带来ABI 稳定性,这意味着基础库将植入系统中,不再包含在App中,应用程序的体积会更小,更多新功能请看下文。

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或更早版本的体积小。具体的大小差异取决于应用程序使用的框架的数量。

Swift

@dynamicCallable属性允许你调用命名的类型,就像使用简单的语法糖调用函数一样。主要的应用场景是动态语言互操作性。

例如:

@dynamicCallable struct ToyCallable {    func dynamicallyCall(withArguments: [Int]) {}    func dynamicallyCall(withKeywordArguments: KeyValuePairs\u0026lt;String, Int\u0026gt;) {}}let x = ToyCallable()x(1, 2, 3)// Desugars to `x.dynamicallyCall(withArguments: [1, 2, 3])`x(label: 1, 2)// Desugars to `x.dynamicallyCall(withKeywordArguments: [\u0026quot;label\u0026quot;: 1, \u0026quot;\u0026quot;: 2])`

现在支持标识KeyPath(.self),一个引用其整个输入值的WritableKeyPath:

let id = \\Int.selfvar x = 2print(x[keyPath: id]) // Prints \u0026quot;2\u0026quot;x[keyPath: id] = 3print(x[keyPath: id]) // Prints \u0026quot;3\u0026quot;

在Swift 5之前,你可以编写一个带有可变参数的枚举:

enum X {    case foo(bar: Int...) }func baz() -\u0026gt; X {    return .foo(bar: 0, 1, 2, 3) } 

现在如果这么做会出错。相反,现在参数改成了一个数组,并且需要显式传入数组:

enum X {    case foo(bar: [Int]) } func baz() -\u0026gt; X {    return .foo(bar: [0, 1, 2, 3]) } 

在Swift 5模式下,可以用?和Optional类型表达式来扁平化生成的Optional,而不是返回嵌套的Optional。

如果类型T符合这些字面量初始化中的一个——例如ExpressibleByIntegerLiteral——并假设literal是一个字面量表达式,那么T(literal)就创建了一个T类型的字面量。

例如,UInt64(0xffff_ffff_ffff_ffff)现在是有效的,而之前它们会导致默认整型字面量类型Int溢出。

字符串插值的性能、清晰度和效率得到了改进。

旧的_ExpressibleByStringInterpolation协议被移除,如果你的代码使用了这个协议,需要更新这些代码,你可以使用#if在Swift 4.2和Swift 5之间条件化代码。例如:

#if compiler(\u0026lt;5)extension MyType: _ExpressibleByStringInterpolation { /*...*/ }#elseextension MyType: ExpressibleByStringInterpolation { /*...*/ }#endif 

Swift标准库

  • DictionaryLiteral类型被重命为KeyValuePairs。

  • 与Objective-C代码桥接的Swift字符串现在会在适当的时候从CFStringGetCStringPtr返回一个非空值,而且从-UTF8String返回的指针与字符串的生命周期(而不是最里面的autorelease pool)相关联。正确的程序应该不会有任何问题,而且还会带来性能方面的提升。但是,它可能会导致以前未经测试的代码暴露出潜在的错误。

  • Sequence协议不再具有SubSequence关联类型。之前返回SubSequence的Sequence方法现在返回的是具体的类型。例如,suffix(_:)现在返回Array。

使用SubSequence的Sequence扩展应该修改为使用具体的类型,或者修改为Collection的扩展(此时SubSequence仍然可用)。

例如:

extension Sequence {    func dropTwo() -\u0026gt; SubSequence {        return self.dropFirst(2)    }}

变为:

extension Sequence {    func dropTwo() -\u0026gt; DropFirstSequence\u0026lt;Self\u0026gt; {         return self.dropFirst(2)    }}

或者:

extension Collection {    func dropTwo() -\u0026gt; SubSequence {        return self.dropFirst(2)    }}
  • String结构的原生编码从UTF-16切换到UTF-8,这样提高了String.UTF8View的性能(相对于String.UTF16View)。

Swift包管理器

  • 现在,在使用Swift 5 Package.swift工具版本时,可以声明一些常用的特定于目标的构建设置。新的设置也可以基于平台和构建配置进行条件化。构建设置支持Swift和C语言定义、C语言头文件搜索路径、链接库和链接框架。

  • 现在,在使用Swift 5 Package.swift工具版本时,可以为Apple平台自定义最低部署目标。如果程序包的任何依赖项指定的最小部署目标大于程序包自身的最低部署目标,就会抛出错误。

  • 新的依赖项镜像功能允许顶层包覆盖依赖项URL。

可以使用以下命令设置镜像:

$ swift package config set-mirror \\--package-url \u0026lt;original URL\u0026gt; --mirror-url \u0026lt;mirror URL\u0026gt;
  • swift test命令提供了–enable-code-coverage标志,它生成的代码覆盖率数据也适用于其他代码覆盖工具。生成的代码覆盖率数据放在//codecov目录中。

  • Swift 5不再支持Swift 3 Package.swift工具版本。Swift 3 Package.swift工具版本的软件包应该升级到更新的工具版本。

  • 针对较大的程序包的包管理器操作现在明显更快。

  • Swift包管理器提供了一个新的–disable-automatic-resolution标志,当Package.resolved条目与Package.swift清单文件中指定的依赖项版本不兼容时,该标志会强制包解析失败。在进行持续集成时,如果需要检查包的Package.resolved是否已过期,这项功能会非常有用。

  • swift run命令提供了一个新的——repl选项,它将启动Swift REPL,支持导入包的库目标。这样你就可以轻松地试用API,而无需构建调用该API的可执行文件。

Swift编译器

  • 现在,对于优化(-O和-Osize)构建,默认情况下在运行时强制执行独占内存访问。违反排他性的程序将在运行时出现“overlapping access”诊断消息。你可以使用命令行标志禁用它:-enforce-exclusivity = unchecked,但这样做可能会导致未定义的行为。运行时违反排他性通常是由于同时访问类属性、全局变量(包括顶层代码中的变量)或通过转义闭包捕获的变量。

  • Swift 3模式已被删除。-swift-version标志支持的值为4、4.2和5。

  • 在Swift 5模式中,在迭代使用Objective-C声明或来自系统框架的枚举时需要处理未知的case——可能在将来添加的case,或者可能在Objective-C实现文件中私下定义的case。Objective-C允许在枚举中存储任意值,只要它们与底层类型匹配即可。可以使用新的@unknown来处理这些未知case,当然也可以使用普通的default来处理它们。

如果你已在Objective-C中定义了自己的枚举,并且不需要客户端处理未知case,那么可以使用NS_CLOSED_ENUM宏而不是NS_ENUM。Swift编译器就会识别出来,不要求在迭代时提供默认case。

在Swift 4和4.2模式下,你仍然可以使用@unknown。如果省略了它并传入了一个未知的值,程序将在运行时出错,这与Xcode 10.1中的Swift 4.2的行为是一样的。

  • 现在,默认参数打印在SourceKit生成的Swift模块接口中,而不只是使用占位符。

  • unowned和unowned(unsafe)变量现在支持Optional。

已知问题

  • 如果引用了UIAccessibility的成员,Swift编译器会在进行到“Merge swiftmodule”这个构建步骤时崩溃。构建日志会包含这样一条消息:
Cross-reference to module 'UIKit'... UIAccessibility... in an extension in module 'UIKit'... GuidedAccessError

包含NS_ERROR_ENUM枚举的其他类型也可能出现这个问题,但UIAccessibility是最常见的。

解决方法:使用“Swift Compiler - Code Generation”下的Whole Module编译模式选项重新构建,这是大多数发布配置的默认设置。

  • 为了减少Swift元数据占用的空间,Swift中定义的便捷初始化器现在只在调用Objective-C中定义的指定初始化器时提前分配对象。在大多数情况下,这对程序没有任何影响,但是如果从Objective-C调用便捷初始化器,就会释放+alloc初始分配的资源。对于不希望发生对象替换的初始化器用户来说,这可能是有问题的。例如,在使用initWithCoder:时,NSKeyedUnarchiver的实现可能会不正确,如果它调用了init(coder:)的Swift实现,并且对象图中包含了环。

  • 如果KeyPath字面量引用了在Objective-C中定义的属性或者在Swift中使用@objc和动态修饰符定义的属性,那么编译可能会失败,并抛出“unsupported relocation of local symbol ‘L_selector’”的错误,或者KeyPath可能无法在运行时生成正确的哈希值。

解决方法:你可以自己定义非@objc包装器属性,指向这个KeyPath。生成的KeyPath与引用原始Objective-C属性的KeyPath不一样,但使用效果是一样的。

  • 某些项目可能会遇到编译时回归问题。

  • Swift命令行项目在启动时会崩溃,错误为“dyld: Library not loaded”。

解决方法:添加用户自定义的构建设置SWIFT_FORCE_STATIC_LINK_STDLIB = YES。

已解决的问题

  • 扩展绑定现在支持嵌套类型的扩展,这些类型本身是在扩展内定义的。之前可能会因为声明顺序问题而失败,出现“undeclared type”错误。

  • 在Swift 5模式下,返回Self的类方法不能再使用返回具体类类型(非final)的方法来覆盖。这类代码不是类型安全的,需要将它们改掉。

例如:

class Base {     class func factory() -\u0026gt; Self { /*...*/ }} class Derived: Base {    class override func factory() -\u0026gt; Derived { /*...*/ } } 
  • 在Swift 5模式下,现在明确禁止声明与嵌套类型同名的静态属性,而之前可以在泛型类型的扩展中进行这样的声明。

例如:

struct Foo\u0026lt;T\u0026gt; {}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 }}
  • 现在可以在子类中正确继承具有可变参数的指定初始化器。

  • 在Swift 5模式下,@autoclosure参数不能再被转发给另一个函数调用的@autoclosure参数。相反,你必须使用括号显式调用函数值。调用将被包含在一个隐式闭包中,保证了与Swift 4模式相同的行为。

例如:

func foo(_ fn: @autoclosure () -\u0026gt; Int) {}func bar(_ fn: @autoclosure () -\u0026gt; Int) {    foo(fn) // Incorrect, `fn` can’t be forwarded and has to be called.    foo(fn()) // OK} 
  • 现在完全支持复杂的递归类型定义,包括之前在运行时会导致死锁的类和泛型。

  • 在Swift 5模式下,在将Optional值转换为通用占位符类型时,编译器在展开值时会更加保守。这种转换结果现在更接近于非通用上下文中获得的结果。

例如:

func forceCast\u0026lt;U\u0026gt;(_ value: Any?, to type: U.Type) -\u0026gt; U {    return value as! U } let value: Any? = 42print(forceCast(value, to: Any.self))// Prints \u0026quot;Optional(42)\u0026quot;// (Prior to Swift 5, this would print \u0026quot;42\u0026quot;.)print(value as! Any)// Prints \u0026quot;Optional(42)\u0026quot;
  • 协议现在可以将符合类型限定为给定类的子类。支持两种等效形式:
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 \u0026lt; 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

更多内容,请关注前端之巅。

Swift 5新特性详解:ABI 稳定终于来了!相关推荐

  1. python3.9性能_Python3.9新特性详解

    本文主要介绍Python3.9的一些新特性,如:更快速的进程释放,性能的提升,简便的新字符串函数,字典并集运算符以及更兼容稳定的内部API,详细如下: 字典并集和可迭代更新 字符串方法 类型提示 新的 ...

  2. 还在用JDK6的同学,来看看JDK13新特性详解吧

    点击上方"搜云库技术团队"关注,选择"设为星标" 回复"面试题"或"1024"获取 4T 学习资料 在 JDK 版本的世 ...

  3. java11 新特性 详解

    为什么80%的码农都做不了架构师?>>>    引言: 点击-->java10 新特性 详解 点击-->java9 新特性 详解 点击-->java8 新特性 详解 ...

  4. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高...

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  5. Java基础学习总结(33)——Java8 十大新特性详解

    Java8 十大新特性详解 本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API ...

  6. Java9 新特性 详解

    目录 Java9 新特性 详解 1.Java9新特性之---目录结构 2.Java9新特性之---JShell工具 3.Java9新特性之---模块化 4.Java9新特性之---多版本兼容Jar包 ...

  7. oracle dataguard详解,Oracle 19c 新特性详解:DataGuard 中ADG的自动DML重定向

    Oracle 19c 新特性详解:DataGuard 中ADG的自动DML重定向 在前面的文章<Oracle 19c 十大新特性一览>中,我们曾经提到 Oracle 19c的一个重要增强, ...

  8. java8-stream新特性详解及实战

    Java8 Stream新特性详解及实战 背景介绍 在阅读Spring Boot源代码时,发现Java 8的新特性已经被广泛使用,如果再不学习Java8的新特性并灵活应用,你可能真的要out了.为此, ...

  9. Java EE 8的五大新特性详解

    Java EE 8的五大新特性详解 2018.4.3 版权声明:本文为博主chszs的原创文章,未经博主允许不得转载. Java EE 8带来了很多新特性,其中最好的新特性有下面五个. 备受期待的Ja ...

最新文章

  1. 混合粒子群算法原理通俗讲解
  2. 为什么现在小学生都学计算机编程了,为何要在小学阶段开展编程教育?
  3. Oracle对象之序列
  4. hdoj1242(dfs 剪枝 解法)
  5. HTML转存问题测试
  6. 20175213 2018-2019-2 《Java程序设计》第4周学习总结
  7. linux命令详解——iostat
  8. 事务隔离级别动图演示
  9. mysql+跨服务器+写入_MySQL中使用FREDATED引擎实现跨数据库服务器、跨实例访问
  10. 通过Resource file本地化SharePoint用户界面
  11. opencv 直方图均等化
  12. Linux下多进程服务端客户端模型二(粘包问题与一种解决方法)
  13. JavaScript 图片切换展示效果
  14. linux 加速播放软件,VirtualBox 6.1首次推出Linux 5.4支持,加速的视频播放及更多功能...
  15. 基于信息熵确立权重的topsis法_一种基于加权秩和比法的光伏并网逆变器多性能指标评价方法研究...
  16. LeetCode Two Sum
  17. 人脸识别库-于仕琪老师库地址
  18. 给新安装的RHEL8虚拟机 安装 vmware tools
  19. 【转】视频编码与封装方式详解
  20. mysql删除日志文件_mysql删除日志文件,定时清理日志

热门文章

  1. error: L6235E: More than one section matches selector - cannot all be FIRST/LAST.
  2. nginx二进制编译-启动脚本编写
  3. Java SSM框架之MyBatis3(六)MyBatis之参数传递
  4. 《常见问题集》Maven
  5. 三、常用行内元素与块元素
  6. C语言-01基础语法
  7. sql server 约束
  8. [转]程序员最容易犯的几个技术上的错误
  9. vue.js页面刷新出现闪烁问题的解决
  10. 异常:Invalid character found in the request target. The valid characters are defined in RFC 3986