在Objective-C里,声明变量的时候,我们可以用下面的形式表达类型和protocol的关系:
id<Protocol1, Protocol2>
Base<Protocol>*
例如,第一个就表示任意遵从Protocol1
和Protocol2
的类型,第二个则表示遵从Protocol
的Base
类。为了实现同样的功能,SE-0156为Swift 4添加了下面的特性。
用AnyObject约束任意遵从protocol的类
当我们要约束任意一个遵从P
的类时,可以这样:
protocol P {}
struct S : P {}
class C : P {}
class D { }
let u: AnyObject & P = C()
let v: P & AnyObject = C()
在上面的例子里,AnyObject
表示任意一个class
,P
表示要遵从的protocol
,用&
把它们连接起来,就达成了我们要对类型进行的约束。不过,就像你看到的一样,它们的先后并没有关系。理解了它的含义之后,就不难理解,下面的代码,都会触发编译错误:
// !! Compile time error: `S` is not a class !!
let t: AnyObject & P = S()
// !! Compile time error: `D` is not conform to P !!
let w: AnyObject & P = D()
用具体的类名约束遵从protocol的类以及派生类
除了AnyObject
之外,我们也可以限制某个遵从了protocol的具体类以及它的派生类,像这样:
protocol P {}
struct S : P {}
class C {}
class D: P {}
class E: C, P {}
let w: C & P = E()
其中,C & P
这样的写法,表示遵从了protocol P
的类C
以及C
的派生类。因此,下面两种情况都会导致编译错误:
首先,不能限制struct
类型的protocol
约束:
let u: S & P
其次,不是的C
的派生类无法通过编译:
let v: C & P = D()
另外,当我们在protocol
约束中,同时使用了AnyObject
和具体的类名,则具体的类名会覆盖AnyObject
,也就是说,下面这两种表达方式是相同的:
let w: C & P = E()
let w: AnyObject & C & P = E()
而下面的代码同样无法通过编译:
let v: AnyObject & C & P = D()
实际上,关于protocol-constraints的用法,还有一些更复杂的情况,例如,在约束中串联多个class
或者typealias
,大家可以在SE-0165中找到关于这个特性的详细规格。这里,我们就不一一展开了,最重要的是,我们要知道,在Swift 4里,多了一种可以进一步约束类型的用法。
带来的潜在影响
基于这个特性,之前的一些Objective-C的代码桥接到Swift 4,采用protocol-constraints语法的时候,会带来源代码的不兼容。来看下面的例子:
@interface MyViewController
- (void)setup:(
nonnull UIViewController<
UITableViewDataSource,
UITableViewDelegate>*)tableViewController;
@end
当上面这段代码桥接到Swift 3时,会忽略掉setup
参数的UITableViewDataSource
和UITableViewDelegate
的约束,变成这样:
class MyViewController {
func setup(
tableViewController: UIViewController) {}
}
于是,在Swift里,我们可以给setup
传递任何一个UIViewController
对象,甚至这个对象没有遵从UITableViewDataSource
和UITableViewDelegate
。
但桥接到Swift 4后,MyViewController
就会变成这样:
class MyViewController {
func setup(
tableViewController:
UIViewController &
UITableViewDataSource &
UITableViewDelegate) {}
}
这时,对于那些没有遵从UITableViewDataSource
和UITableViewDelegate
的UIViewController
对象,如果传递给setup
,就无法通过编译了。
网友评论