Swift4.0 新特性----语法改进
发布时间:2020-12-14 06:08:12 所属栏目:百科 来源:网络整理
导读:注:文章转自这里 1.extension 中可以访问 private 的属性 看下面的代码: struct Date: Equatable,Comparable { private let secondsSinceReferenceDate: Double static func ==(lhs: Date,rhs: Date) - Bool { return lhs.secondsSinceReferenceDate == rh
注:文章转自这里
1.extension 中可以访问 private 的属性
看下面的代码:
struct Date: Equatable,Comparable { private let secondsSinceReferenceDate: Double static 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 了,这是最好的结果。 2.类型和协议的组合类型
看下面的代码:
protocol Shakeable { func shake() } extension UIButton: Shakeable { /* ... */ } extension UISlider: Shakeable { /* ... */ } func shakeEm(controls: [???]) { for control in controls where control.isEnabled {} control.shake() } 在 Swift 3 中,[]里的 ??? 应该写什么呢?如果写 UIControl,那么 control.shake() 就会报错;如果写 Shakeable,那么 control.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.isEnabled { control.shake() } } 把它声明为了 UIControl & Shakeable 类型。OK,圆满解决。
另外,iOS SDK 中的 API 也用这个特性做了优化,例如:
// Objective-C API @interface NSCandidateListTouchBarItem<CandidateType> : NSTouchBarItem @property (nullable,weak) NSView <NSTextInputClient> *client; @end 这个 API 的 Objective-C 版本是没有问题的,可以知道 client 属性既是一个 NSView,又符合 NSTextInputClient 协议。然而它对应的 Swift 3 版本仅仅是一个 NSView 类型: class NSCandidateListTouchBarItem<CandidateType: AnyObject> : NSTouchBarItem { var client: NSView? } 在 Swift 4 中,这类 API 做了优化,类型的声明就更加严谨,改成了: class NSCandidateListTouchBarItem<CandidateType: AnyObject> : NSTouchBarItem { var client: (NSView & NSTextInputClient)? }
|