Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
510 views
in Technique[技术] by (71.8m points)

swift - How do I declare a variable that has a type and implements a protocol?

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

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.

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

@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:

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"

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}

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

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:

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...