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

时间:2014-08-09 01:44:45

标签: swift protocols

我的应用程序有详细视图控制器的协议,声明它们必须具有viewModel属性:

protocol DetailViewController: class {
    var viewModel: ViewModel? {get set}
}

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

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

class MapViewController: UIViewController, DetailViewController {
    // ...
}

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

很遗憾,我无法找到有关如何执行此操作的任何文档。在Objective-C中,这将是微不足道的:

@property (strong, nonatomic) UIViewController<DetailViewController>;

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

class MasterViewController<T where T:UIViewController, T:DetailViewController>: UITableViewController {
    var detailViewController: T?
    // ...
}

但后来我得到一个错误,说&#34; Class&#39; MasterViewController&#39;没有实现其超类的必要成员&#34;

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

3 个答案:

答案 0 :(得分:13)

我认为您可以通过向UIViewController添加(空)扩展程序,然后使用空扩展程序和detailViewController的组合协议指定DetailViewController属性来实现目标。像这样:

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}

现在UIViewController的所有子类都满足协议UIViewControllerInject。然后,只需:

typealias DetailViewControllerComposed = protocol<DetailViewController, UIViewControllerInject>

class MasterViewController : UITableViewController {
  var detailViewController : DetailViewControllerComposed?
  // ...
}

但是,这并不是特别自然的&#39;。

===编辑,添加===

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

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}

protocol DetailViewController : UIViewControllerInject { /* ... */ }

现在您不需要明确撰写某些内容(我的DetailViewControllerComposed),并且可以使用DetailViewController?作为detailViewController的类型。

答案 1 :(得分:10)

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

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

等效于Objective-C语法:

Application

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

AsyncTask

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

答案 2 :(得分:2)

另一种方法是为实现协议的相应UIKit视图控制器引入中间基类:

class MyUIViewControler : UIViewController, DetailViewController ...
class MyUITableViewController : UITableViewController, DetailViewController ...

然后从这些视图控制器继承视图控制器,而不是UIKit视图控制器。

这也不自然,但它并没有像GoZoner建议的那样强迫所有UIViewControllers满足UIViewControllerInject协议。