如何要求协议只能由特定类采用

emr*_*s57 79 generics protocols swift

我想要这个协议:

protocol AddsMoreCommands {
     /* ... */
}
Run Code Online (Sandbox Code Playgroud)

只能从继承自类的类中采用UIViewController.这个页面告诉我,我可以通过编写指定它只被类(而不是结构)采用

protocol AddsMoreCommands: class {
}
Run Code Online (Sandbox Code Playgroud)

但是我看不出如何要求它只被特定的类所采用.该页后面讨论了where为协议扩展添加条款以检查一致性,但我也看不出如何适应它.

extension AddsMoreCommands where /* what */ {
}
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点?谢谢!

Roe*_*e84 103

protocol AddsMoreCommands: class {
    // Code
}

extension AddsMoreCommands where Self: UIViewController {
    // Code
}
Run Code Online (Sandbox Code Playgroud)

  • 我几乎拥有它...我写了'self`而不是`Self` :-(非常感谢,这很好! (4认同)
  • 如果您需要在协议中包含属性,这将不起作用,因为扩展不能包含存储的属性. (3认同)

rgk*_*shi 70

这也可以在没有扩展的情况下实现:

protocol AddsMoreCommands: class where Self: UIViewController {
   // code
}
Run Code Online (Sandbox Code Playgroud)

编辑2017/11/04:正如Zig所指出的,这似乎在Xcode 9.1上产生了警告.目前在Swift项目(SR-6265)上报告了一个问题,要求删除警告,我会密切关注它并相应地更新答案.

编辑2018/09/29:class如果存储实例的变量需要较弱(例如委托),则需要.如果你不需要弱变量,你可以省略class并只写下面的内容,不会有任何警告:

protocol AddsMoreCommands where Self: UIViewController {
   // code
}
Run Code Online (Sandbox Code Playgroud)

  • 我点击一个两年前的问题并找到一小时前发布的完美解决方案,这有多么巧合 (4认同)
  • 从Xcode 9.1开始,只有类的协议现在使用`AnyObject`而不是`class`.`protocol AddsMoreCommands:AnyObject where Self:UIViewController {// code}` (2认同)

Mas*_*ker 47

由于上一个答案中存在问题,我最终得到了这个声明:

protocol AddsMoreCommands where Self : UIViewController { 
    // protocol stuff here  
}
Run Code Online (Sandbox Code Playgroud)

Xcode 9.1中没有警告

  • 要避免类型转换,您可以这样做:`typealias AddsMoreCommandsViewController = UIViewController&AddsMoreCommands` (8认同)
  • 如果我错了,请纠正我,但是对于上面的解决方案(在Xcode 9.1及更高版本中生成警告)的问题是,您不能将委托声明为弱? (4认同)

Woj*_*lik 13

现在,在Swift 5中,您可以通过以下方法实现此目的:

protocol AddsMoreCommands: UIViewController {
     /* ... */
}
Run Code Online (Sandbox Code Playgroud)

非常方便。