猿问

即使协议要求给定类型,也必须强制转换

我有以下代码:


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?


月关宝盒
浏览 449回答 3
3回答

慕容708150

采用该协议Fooable告诉编译器此特定UIViewController响应foo(),至少如此。在相反的结论,Fooable并没有成为UIViewController必然。如果受影响的类不是,约束Self: UIViewController只是编译器在编译时抱怨的另一信息。UIViewController在您的情况下SampleViewController,Fooable对编译器进行批注仅知道SampleViewController对作出响应foo()。它不知道类型实际上是的子类UIViewController。因此,如果要访问具体类的属性,请不要在协议中为具体类注释。但是,您可以将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。更新:在Swift 5中,实现了对超类约束协议的支持。

莫回无

常见的模式是这样做的:protocol Fooable {    func foo()    var viewController: UIViewController}class SampleViewController: UIViewController, Fooable {    func foo() {        print("foo")    }    var viewController: UIViewController { return self }}在Swift 4中,您可以使类型为var UIViewController & Fooable。在Swift 3中使用上述技巧。
随时随地看视频慕课网APP
我要回答