为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

月关宝盒 2019-11-04 09:58:55
我有以下代码:import UIKitprotocol 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?
查看完整描述

3 回答

?
慕容708150

TA贡献1831条经验 获得超4个赞

采用该协议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中,实现了对超类约束协议的支持。


查看完整回答
反对 回复 2019-11-04
?
莫回无

TA贡献1865条经验 获得超7个赞

常见的模式是这样做的:


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中使用上述技巧。


查看完整回答
反对 回复 2019-11-04
  • 3 回答
  • 0 关注
  • 443 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信