protocol 组合
其实 Any 是 protocol<> 的同名写法,可以用来表示任意类型。protocol<> 的标准语法形式是:protocol<ProtocolA, ProtocalB>
。protocol 组合是可以使用 typealias 来命名的,这样可以提高我们的代码可读性:
1
typealise ServerType = protocol<URLDestination, DataResolver>
可选接口 (optional protocol)
一种方法是标记 protocol 为@objc
, 则可以使用 Objective-C 中的关键字optional
:
1
2
3
@objc protocol OptionalProtocol {
optional func optionalMethod()
}
但是缺点是,@objc
修饰的 protocol 只能提供给类使用,struct 和 enum 不能继承。我们可以用另一种办法 extension protocol,给 protocol 的方法提供默认实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
protocol OptionalProtocol {
func optionalMethod()
}
extension OptionalProtocol {
func optionalMethod() {
...
}
}
Class A: OptionalProtocol { }
let a = A()
a.optionalMethod()
接口扩展之后,类实现接口的默认方法实现,即是扩展里的实现方法。这个写法也有个坏处,其他的使用者可能会不了解接口已经做过扩展,所以协议和扩展尽量写在同一个文件中,并注释清楚。
protocol 扩展和方法覆盖
protocol 扩展可以为 protocol 类型提供额外的方法实现,就如 optional 实现原理一样。我们也可以在具体类的实现中覆盖这些方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protocol Progress {
func start()
}
extension Progress {
func start() {
print("nothing")
}
}
class Request: Progress {
func start() {
print("request")
}
}
let req = Request()
req.start()
// Print:
// request
那现在再给 Progress 扩展一个定义中不含有的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
extension Progress {
func cancel() {
print("nothing")
}
}
class Request: Progress {
func start() {
print("request")
}
func cancel() {
print("cancel")
}
}
let req = Request()
req.cancel() ==> cancel
(req as Progress).cancel() ==> nothing
可以看到,对于类和接口里都实现了方法,且方法不在接口定义中时,实际调用时根据当前类型判断的,如果是 Request 则调用类中的方法,如果是 Protocol 则调用协议扩展中的方法。
Protocol Assosiated Type
我们可以在 protocol 中添加一个 associatedtype
类型关联,实现协议的类型需要完成协议中的类型指定。
1
2
3
4
5
6
7
8
protocol StorableInfo {
associatedtype InfoKey
}
class Request: StorableInfo {
typealias InfoKey: String
var storedInfo: [InfoKey: Any]
}
在 Swift 4.0 中引入了 where
条件语句, 这样就可以更加灵活的运用一些泛型类型。
1
2
3
4
5
6
7
8
protocol StorableInfo {
associatedtype InfoKey where InfoKey: Hashable
}
// 在以前是编译不通过的,因为 M.InfoKey 不一定符合 Hashable
class Request<M: StorableInfo> {
var stroedInfo: [M.InfoKey: Any]
}
Self、.self 和 .Type
- .self 实际上是返回当前对象,如果是类型就返回当前类的元类型:
1
2
3
4
let user = User()
user.self == user // ==> true
let userType = User.self // User.Type
- Self 一般使用在接口中,用来表明实现接口本身的对象:
1
2
3
4
5
6
7
8
9
protocol Producer {
static func instance() -> Self
}
extension User: Producer {
static func instance() -> Self {
return self.init()
}
}
这里有个问题,使用 self.init() 返回才能符合 Self,而不能使用 User() ,虽然这里 User 和 Self 等价。原因是在 non-final class 中实现方法,这个类是有可能被继承的,而如果使用 User() 这种写法,显然子类调用之后就不会返回子类的对象了。
- .Type 是表明一个类的元类型,现在可以使用
type(of:)
方法来获得指定实例的元类型:
1
2
let type: User.Type = User.self
let metaType = type(of: user) ===> User.Type