作者:刘铎
本文为原创文章,转载请注明作者及出处

WWDC 2017 带来了很多惊喜。Swift 4 也伴随着 Xcode 9 测试版来到了我们的面前,很多强大的新特性非常值得我们期待在正式项目中去使用它。因为 Swift 4 是开源的,如果你关注 swift-evolution 这个项目的话,就应该已经提前了解到它的新特性了。本文参考了 WWDC 2017 以及各种资料,,从语法、字符串、标准库、构建过程等方面,把 Swift 4 的这些新特性一一列举出来做介绍和分析,让他们毫无保留地展现在你眼前。

一、语法改进

extension 中可以访问 private 的属性

考虑以下代码:

struct Date: Equatable, Comparable {private let secondsSinceReferenceDate: Doublestatic func ==(lhs: Date, rhs: Date) -> Bool {return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate}static func <(lhs: Date, rhs: Date) -> Bool {return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate}
}

上面代码定义了一个 Date 结构体,并实现 Equatable 和 Comparable 协议。为了让代码更清晰,可读性更好,一般会把对协议的实现放在单独的 extension 中,这也是一种非常符合 Swift 风格的写法,如下:

struct Date {private let secondsSinceReferenceDate: Double
}
extension Date: Equatable {static func ==(lhs: Date, rhs: Date) -> Bool {return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate}
}
extension Date: Comparable {static func <(lhs: Date, rhs: Date) -> Bool {return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate}
}

但是在 Swift 3 中,编译就报错了,因为 extension 中无法获取到 secondsSinceReferenceDate 属性,因为它是 private 的。于是在 Swift 3 中,必须把 private 改为 fileprivate。

struct Date {fileprivate let secondsSinceReferenceDate: Double
}
...

但是如果用 fileprivate,属性的作用域就会比我们需要的更大,可能会不小心造成属性的滥用。

在 Swift 4 中,private 的属性的作用域扩大到了 extension 中,并且被限定在了 struct 和 extension 内部,这样就不需要再改成 fileprivate 了,这是最好的结果。

类型和协议的组合类型

考虑以下代码:

protocol Shakeable {func shake()
}extension UIButton: Shakeable { /* ... */ }
extension UISlider: Shakeable { /* ... */ }func shakeEm(controls: [???]) {for control in controls where control.state.isEnabled {}control.shake()
}

在 Swift 3 中,这里的 ??? 应该写什么呢?如果写 UIControl,那么 control.shake() 就会报错;如果写 Shakeable,那么 control.state.isEnabled 就会报错。其实我们也可以这样写:

func shakeEm(controls: [UIControl]) {for control in controls where control.isEnabled {if control is Shakeable {(control as! Shakeable).shake()}}
}

这样写虽然可以跑通了,但是很丑陋。

在 Swift 4 中,可以把类型和协议用 & 组合在一起作为一个类型使用,就可以像下面这样写了:

protocol Shakeable {func shake()
}extension UIButton: Shakeable { /* ... */ }
extension UISlider: Shakeable { /* ... */ }func shakeEm(controls: [UIControl & Shakeable]) {for control in controls where control.state.isEnabled {control.shake()}// Objective-C API
@interface NSCandidateListTouchBarItem<CandidateType> : NSTouchBarItem
@property (nullable, weak) NSView <NSTextInputClient> *client;
@end
}

把它声明为了 UIControl & Shakeable 类型。OK,圆满解决。

PS:
这个代码例子是 WWDC 2017 的 PPT 中的,上面的代码有点问题,control.state.isEnabled 这句代码中,state 是没有 isEnabled 这个属性的,改为 control.isEnabled 就可以了。看来苹果的工程师做 PPT 有时候还是不太严谨。

另外,iOS SDK 中的 API 也用这个特性做了优化,例如:


这个 API 的 Objective-C 版本是没有问题的,可以知道 client 属性既是一个 NSView,又符合 NSTextInputClient 协议。然而它对应的 Swift 3 版本为:

class NSCandidateListTouchBarItem<CandidateType: AnyObject> : NSTouchBarItem {var client: NSView?
}

仅仅是一个 NSView 类型 /(ㄒoㄒ)/~~

在 Swift 4 中,这类 API 做了优化,改成了:

class NSCandidateListTouchBarItem<CandidateType: AnyObject> : NSTouchBarItem {var client: (NSView & NSTextInputClient)?
}

这样类型的声明就更加严谨了。

Associated Type 可以追加 Where 约束语句

在 Swift 4 中可以在 associatedtype 后面声明的类型后追加 where 语句

associatedtype Element where <xxx>

看下面是 Swift 4 标准库中 Sequence 中 Element 的声明:

protocol Sequence {associatedtype Element where Self.Element == Self.Iterator.Element// ...
}

它限定了 Sequence 中 Element 这个类型必须和 Iterator.Element 的类型一致。

通过 where 语句可以对类型添加更多的约束,使其更严谨,避免在使用这个类型时做多余的类型判断。

新的 Key Paths 语法

先来看看 Swift 3 中 Key Paths 的写法:

@objcMembers class Kid: NSObject {dynamic var nickname: String = ""dynamic var age: Double = 0.0dynamic var friends: [Kid] = []
}var ben = Kid(nickname: "Benji", age: 5.5)let kidsNameKeyPath = #keyPath(Kid.nickname)let name = ben.valueForKeyPath(kidsNameKeyPath)
ben.setValue("Ben", forKeyPath: kidsNameKeyPath)

Swift 4 中创建一个 KeyPath 用 \ 作为开头:

\Kid.nickname

当编译器可以推导出类型时,可以省略基础类型部分:

\.nickname

上面的代码在 Swift 4 中就可以这样写:

struct Kid {var nickname: String = ""var age: Double = 0.0var friends: [Kid] = []
}var ben = Kid(nickname: "Benji", age: 8, friends: [])let name = ben[keyPath: \Kid.nickname]
ben[keyPath: \Kid.nickname] = "BigBen"

相比 Swift 3,Swift 4 的 Key Paths 具有以下优势:

  1. 类型可以定义为 class、struct
  2. 定义类型时无需加上 @objcMembers、dynamic 等关键字
  3. 性能更好
  4. 类型安全和类型推断,例如 ben.valueForKeyPath(kidsNameKeyPath) 返回的类型是 Any,ben[keyPath: \Kid.nickname] 直接返回 String 类型
  5. 可以在所有值类型上使用

下标支持泛型

有时候会写一些数据容器,Swift 支持通过下标来读写容器中的数据,但是如果容器类中的数据类型定义为泛型,以前的下标语法就只能返回 Any,在取出值后需要用 as? 来转换类型。Swift 4 定义下标也可以使用泛型了。

struct GenericDictionary<Key: Hashable, Value> {private var data: [Key: Value]init(data: [Key: Value]) {self.data = data}subscript<T>(key: Key) -> T? {return data[key] as? T}
}let dictionary = GenericDictionary(data: ["Name": "Xiaoming"])let name: String? = dictionary["Name"] // 不需要再写 as? String

二、字符串

Unicode 字符串在计算 count 时的正确性改善

在 Unicode 中,有些字符是由几个其它字符组成的,比如 é 这个字符,它可以用 \u{E9} 来表示,也可以用 e 字符和上面一撇字符组合在一起表示 \u{65}\u{301}

考虑以下代码:

var family = "

读书笔记-最全的 Swift 4 新特性解析相关推荐

  1. naarray查询 swift_最全的 Swift 4 新特性解析

    作者:刘铎 本文为原创文章,转载请注明作者及出处 WWDC 2017 带来了很多惊喜.Swift 4 也伴随着 Xcode 9 测试版来到了我们的面前,很多强大的新特性非常值得我们期待在正式项目中去使 ...

  2. 《ASP.NET Core In Action》读书笔记系列五 ASP.NET Core 解决方案结构解析1

    <ASP.NET Core In Action>读书笔记系列五 ASP.NET Core 解决方案结构解析1 参考文章: (1)<ASP.NET Core In Action> ...

  3. Atitit.swift 的新特性 以及与java的对比 改进方向attilax 总结

    Atitit.swift 的新特性 以及与java的对比 改进方向attilax 总结 1. defer关键字1 2. try!形式存在的"不失败"机制3 3. Guard 4 4 ...

  4. Swift 5新特性详解:ABI 稳定终于来了!

    近日,苹果开发者博客更新了一篇关于Swift 5的文章,带来了Swift 5新特性的消息,其中最受开发期待的莫过于iOS 12.2将带来ABI 稳定性,这意味着基础库将植入系统中,不再包含在App中, ...

  5. GreenDao3.0新特性解析(配置、注解、加密)

    Greendao3.0release与7月6日发布,其中最主要的三大改变就是:1.换包名 2.实体注解 3.加密支持的优化 本文里面会遇到一些代码示例,就摘了官方文档和demo里的例子了,因为他们的例 ...

  6. 【转】Silverlight 3 Beta 新特性解析(7)- Child Window和Shader Effect篇

    前提条件: 阅读本文之前请确认你已经安装了如下软件 Visual Studio 2008 (Express) SP1 Silverlight 3 Tools For Visual Studio Mic ...

  7. python3.8新特性 逻辑表达式_Python3.8正式发布!新特性解析在这里

    Python3.8正式发布!新特性解析在这里 诗书塞外 Python程序员 10月14日,Python 3.8 正式版发布.这也意味着一个Python开发周期的结束,和另一个开发周期的开始.Pytho ...

  8. JavaScript ES2021 新特性解析

    JavaScript ES2021 新特性解析 新特性列表 String.prototype.replaceAll Promise.any 逻辑运算符和赋值表达式 数值分隔符 Intl.ListFor ...

  9. 资源放送丨《 先睹为快!Oracle 20c新特性解析》PPT视频

    前段时间,墨天轮邀请到了云和恩墨CTO.ACDU核心专家."Oracle百科全书" 杨廷琨 老师分享<先睹为快!Oracle 20c新特性解析>,在这里我们共享一下PP ...

最新文章

  1. 改进C#代码之24:通过定义并实现接口替代继承
  2. 【docker】常用命令
  3. python解包操作_Python编程使用*解包和itertools.product()求笛卡尔积的方法
  4. 如何理解Library List
  5. Duilib教程-控件练习
  6. 你是不是已经超纲了?一文解决JavaWeb中要求的HTML,是什么样的?
  7. c语言第四版第8章答案,C语言答案第8章.doc
  8. css3如何链如外部字体,微信小程序引入外部字体总结(针对安卓加载缓慢问题)...
  9. HTML+CSS+Javascript教学视频【0409更新】
  10. 1113 Integer Set Partition(25 分)
  11. 新版本安装包需求汇总
  12. 关于Decorator模式
  13. pyqt自定义信号与槽(Signals and Slots)
  14. AD13如何导出坐标文件
  15. 参数检验与非参数检验的区别
  16. 大伽「趣」说AI:在多个场景中的AI落地实践
  17. 41-MybatisPlus
  18. 电源纹波怎么测量,纹波和噪声的区别
  19. ubuntu下使用netplan配置网络
  20. 使用cv2.VideoCapture()函数捕获笔记本内置摄像头的拍摄画面

热门文章

  1. 第五天:基本swtich语句的用法
  2. 微信小程序 image 图片 组件
  3. phpStorm编写markdown神器
  4. 【小白理财】定投实践结束 - 番外篇
  5. 灌区智能测控一体化闸门系统解决方案
  6. 爬虫s5(爬取请求的cookie)
  7. ROM修改---修改手机开机时间
  8. UVA, 820 Internet Bandwidth
  9. Android平台手机UI应用开发——软件管理器
  10. 批处理脚本,清理磁盘垃圾