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

时间:2023-01-12 20:54:35

My app has a protocol for detail view controllers, stating they must have a viewModel property:

我的app有一个细节视图控制器的协议,说明它们必须有一个viewModel属性:

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

I also have a few different classes that implement the protocol:

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

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

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

My master view controller needs a property that can be set to any UIViewController subclass that implements the DetailViewController protocol.

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

Unfortunately I can't find any documentation on how to do this. In Objective-C it would be trivial:

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

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

It appears that there isn't any syntax available in Swift to do this. The closest I've come is to declare a generic in my class definition:

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

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

But then I get an error saying that "Class 'MasterViewController' does not implement its superclass's required members"

然后我得到一个错误说"类'MasterViewController'没有实现它的超类的必需成员"

This seems like it should be as easy to do in Swift as it is in Objective-C, but I can't find anything anywhere that suggests how I might go about it.

这在Swift中看起来应该和Objective-C中一样容易,但我在任何地方都找不到任何能说明我该怎么做的东西。

3 个解决方案

#1


7  

As of Swift 4, you can now do this.

从Swift 4开始,你现在可以这样做了。

Swift 4 implemented SE-0156 (Class and Subtype existentials).

Swift 4实现了SE-0156(类和子类存在)。

The equivalent of this Objective-C syntax:

这相当于Objective-C的语法:

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

Now looks like this in Swift 4:

现在看来,斯威夫特4:

var detailViewController: UIViewController & DetailViewController

Essentially you get to define one class that the variable conforms to, and N number of protocols it implements. See the linked document for more detailed information.

本质上,你需要定义一个变量遵循的类,以及它实现的N个协议。有关更详细的信息,请参阅链接的文档。

#2


12  

I think you can get there by adding an (empty) extension to UIViewController and then specifying your detailViewController attribute using a composed protocol of the empty extension and your DetailViewController. Like this:

我认为你可以通过向UIViewController添加一个(空的)扩展然后用空扩展和你的detailViewController组成的协议来指定你的detailViewController属性来实现。是这样的:

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}

Now all subclasses of UIViewController satisfy protocol UIViewControllerInject. Then with that, simply:

现在UIViewController的所有子类都满足协议UIViewControllerInject。然后,很简单:

typealias DetailViewControllerComposed = protocol<DetailViewController, UIViewControllerInject>

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

But, this is not particularly 'natural'.

但这并不是特别“自然”。

=== Edit, Addition ===

= = =编辑,添加= = =

Actually, you could make it a bit better if you define your DetailViewController using my suggested UIViewControllerInject. Like such:

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

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}

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

and now you don't need to explicitly compose something (my DetailViewControllerComposed) and can use DetailViewController? as the type for detailViewController.

现在你不需要显式地组合一些东西(我的detailviewcontrollerformed)可以使用DetailViewController吗?作为detailViewController的类型。

#3


2  

Another way would be to introduce intermediate base classes for the appropriate UIKit view controllers that implement the protocol:

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

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

Then you inherit your view controllers from these view controllers, not the UIKit ones.

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

This is not natural either, but it doesn't force all your UIViewControllers to satisfy the UIViewControllerInject protocol as GoZoner suggested.

这也不是自然的,但是它不会强制你所有的UIViewControllerInject协议,就像GoZoner建议的那样。

#1


7  

As of Swift 4, you can now do this.

从Swift 4开始,你现在可以这样做了。

Swift 4 implemented SE-0156 (Class and Subtype existentials).

Swift 4实现了SE-0156(类和子类存在)。

The equivalent of this Objective-C syntax:

这相当于Objective-C的语法:

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

Now looks like this in Swift 4:

现在看来,斯威夫特4:

var detailViewController: UIViewController & DetailViewController

Essentially you get to define one class that the variable conforms to, and N number of protocols it implements. See the linked document for more detailed information.

本质上,你需要定义一个变量遵循的类,以及它实现的N个协议。有关更详细的信息,请参阅链接的文档。

#2


12  

I think you can get there by adding an (empty) extension to UIViewController and then specifying your detailViewController attribute using a composed protocol of the empty extension and your DetailViewController. Like this:

我认为你可以通过向UIViewController添加一个(空的)扩展然后用空扩展和你的detailViewController组成的协议来指定你的detailViewController属性来实现。是这样的:

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}

Now all subclasses of UIViewController satisfy protocol UIViewControllerInject. Then with that, simply:

现在UIViewController的所有子类都满足协议UIViewControllerInject。然后,很简单:

typealias DetailViewControllerComposed = protocol<DetailViewController, UIViewControllerInject>

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

But, this is not particularly 'natural'.

但这并不是特别“自然”。

=== Edit, Addition ===

= = =编辑,添加= = =

Actually, you could make it a bit better if you define your DetailViewController using my suggested UIViewControllerInject. Like such:

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

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}

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

and now you don't need to explicitly compose something (my DetailViewControllerComposed) and can use DetailViewController? as the type for detailViewController.

现在你不需要显式地组合一些东西(我的detailviewcontrollerformed)可以使用DetailViewController吗?作为detailViewController的类型。

#3


2  

Another way would be to introduce intermediate base classes for the appropriate UIKit view controllers that implement the protocol:

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

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

Then you inherit your view controllers from these view controllers, not the UIKit ones.

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

This is not natural either, but it doesn't force all your UIViewControllers to satisfy the UIViewControllerInject protocol as GoZoner suggested.

这也不是自然的,但是它不会强制你所有的UIViewControllerInject协议,就像GoZoner建议的那样。