如何声明具有类型并实现协议的变量?

Fra*_*itt 42 protocols swift

我的应用程序有一个详细视图控制器的协议,说明他们必须有一个viewModel属性:

protocol DetailViewController: class {
    var viewModel: ViewModel? {get set}
}
Run Code Online (Sandbox Code Playgroud)

我还有一些实现协议的不同类:

class FormViewController: UITableViewController, DetailViewController {
    // ...
}

class MapViewController: UIViewController, DetailViewController {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我的主视图控制器需要一个可以设置为UIViewController实现DetailViewController协议的任何子类的属性.

不幸的是我找不到任何关于如何做到这一点的文档.在Objective-C中,它将是微不足道的:

@property (strong, nonatomic) UIViewController<DetailViewController>;
Run Code Online (Sandbox Code Playgroud)

似乎Swift中没有可用的语法来执行此操作.我最接近的是在我的类定义中声明一个泛型:

class MasterViewController<T where T:UIViewController, T:DetailViewController>: UITableViewController {
    var detailViewController: T?
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但后来我得到一个错误,说"Class'MasterViewController'没有实现其超类的必需成员"

这似乎在Swift中应该像在Objective-C中一样容易,但是我找不到任何可以表明我如何去做的事情.

GoZ*_*ner 13

我想你可以通过添加(空)扩展来实现UIViewController,然后detailViewController使用空扩展和你的扩展的组合协议指定你的属性DetailViewController.像这样:

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
Run Code Online (Sandbox Code Playgroud)

现在所有子类都UIViewController满足协议UIViewControllerInject.然后,简单地说:

typealias DetailViewControllerComposed = protocol<DetailViewController, UIViewControllerInject>

class MasterViewController : UITableViewController {
  var detailViewController : DetailViewControllerComposed?
  // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,这并不是特别"自然".

===编辑,加法===

实际上,如果您DetailViewController使用我的建议定义您,可以使它更好一些UIViewControllerInject.像这样:

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}

protocol DetailViewController : UIViewControllerInject { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

现在你不需要明确地组成某些东西(我的DetailViewControllerComposed)并且可以DetailViewController?用作类型detailViewController.

  • 这解决了单向问题 - 但是当你在代码中的某个地方传递`UIViewControllerInject`时,你不能在没有强制转换(`as!`)的情况下调用任何`UIViewController`方法.不幸的是,我认为目前没有办法在ObjC中将变量声明为符合特定协议的某个类.当然,您可以在`UIViewControllerInject`协议中从`UIViewController`声明所需的所有方法. (2认同)

Sen*_*ful 10

从Swift 4开始,您现在可以执行此操作.

Swift 4实现了SE-0156(Class和Subtype存在).

相当于这个Objective-C语法:

@property (strong, nonatomic) UIViewController<DetailViewController> * detailViewController;
Run Code Online (Sandbox Code Playgroud)

现在在Swift 4中看起来像这样:

var detailViewController: UIViewController & DetailViewController
Run Code Online (Sandbox Code Playgroud)

基本上,您可以定义变量符合的一个类,以及它实现的N个协议.有关更多详细信息,请参阅链接文档.