我有以下代码:
import UIKit protocol Fooable: class where Self: UIViewController { func foo() } class SampleViewController: UIViewController, Fooable { func foo() { print("foo") } } let vc1: Fooable = SampleViewController() let vc2: Fooable = SampleViewController() // vc1.show(vc2, sender: nil) - error: Value of type 'Fooable' has no member 'show' // (vc1 as! UIViewController).show(vc2, sender: nil) - error: Cannot convert value of type 'Fooable' to expected argument type 'UIViewController' (vc1 as! UIViewController).show((vc2 as! UIViewController), sender: nil)
注释行无法编译。
为什么UIViewController即使Fooable协议要求,我也必须强制将协议类型对象强制转换为符合该对象类型的对象UIViewController?
UIViewController
Fooable
采用该协议Fooable告诉编译器此特定UIViewController响应foo(),至少不会更多。
foo()
在相反的结论,Fooable并 没有 成为UIViewController必然。
如果受影响的类不是,约束Self: UIViewController只是编译器 在编译时 抱怨的另一信息。UIViewController
Self: UIViewController
在您的情况下SampleViewController,Fooable对编译器进行批注仅知道SampleViewController对作出响应foo()。它不知道类型实际上是的子类UIViewController。
SampleViewController
因此,如果要访问具体类的属性,请不要在协议中为具体类注释。
但是,您可以将show方法和其他常见属性/方法添加到协议中
show
protocol Fooable: class where Self: UIViewController { func foo() func show(_ vc: Fooable, sender: Any?) }
那么您可以使用,Fooable因为编译器知道采用协议的类型会响应该方法。
例如,当您要创建异构但受限制的集合类型时,将类型注释为协议的合适做法是
let array : [CustomStringConvertible] = ["Foo", 1, false] array.forEach{ print("\($0)")}
该代码使用description所有项目都响应的属性打印这三个项目。编译器可识别的三个项目如 其中有一个类型的description财产,还不如String,Int和Bool。
description
String
Int
Bool
更新:
在Swift 5中,实现了对超类约束协议的支持。