八、泛型下标
下标现在可以有泛型参数和返回类型.
最权威的例子莫过于表示 JSON 数据: 你可以定义一个泛型下标来保持调用者期望类型的内容.
struct JSON {
fileprivate var storage: [String:Any]
init(dictionary: [String:Any]) {
self.storage = dictionary
}
subscript<T>(key: String) -> T? {
return storage[key] as? T
}
}
let json = JSON(dictionary: [
"城市名": "北京",
"国家代码": "cn",
"人口": 21_710_000
])
// 没必要用 as? Int
let population: Int? = json["人口"]
另一个例子: Collection 的一个下标接受一个泛型索引序列, 并返回一个这些索引所在的数组:
extension Collection {
subscript<Indices: Sequence>(indices: Indices) -> [Element] where Indices.Element == Index {
var result: [Element] = []
for index in indices {
result.append(self[index])
}
return result
}
}
let words = "我 思 故 我 在".split(separator: " ")
words[[1,2]]
九、NSNumber 桥接
修正部分危险行为当桥接Swift原生数字类型和NSNumber的时候.
import Foundation
let n = NSNumber(value: UInt32(301))
let v = n as? Int8 // nil(Swift 4). Swift 3会是45 (试试看!).
十、类和协议的组合
你现在能写出OC这段 UIViewController <SomeProtocol> * 在Swift中的等价代码, 比如声明这样一个变量,这个变量拥有实体类型并同时遵守若干协议. 语法 let 变量: 某个类 & 协议1 & 协议2.
import Cocoa
protocol HeaderView {}
class ViewController: NSViewController {
let header: NSView & HeaderView
init(header: NSView & HeaderView) {
self.header = header
super.init(nibName: nil, bundle: nil)
}
required init(coder decoder: NSCoder) {
fatalError("not implemented")
}
}
// 不能传一个简单的NSView进去因为不遵守协议
//ViewController(header: NSView())
// 错误: argument type 'NSView' does not conform to expected type 'NSView & HeaderView'
// 必须穿一个 NSView (子类) 同时遵守协议
extension NSImageView: HeaderView {}
ViewController(header: NSImageView()) // 有用