swift VAR restriction of types [duplicate] - swift

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.

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.

As of Swift 4, you can now do this.
Swift 4 implemented SE-0156 (Class and Subtype existentials).
The equivalent of this Objective-C syntax:
#property (strong, nonatomic) UIViewController<DetailViewController> * detailViewController;
Now looks like this in Swift 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.

Another way would be to introduce intermediate base classes for the appropriate UIKit view controllers that implement the protocol:
class MyUIViewControler : UIViewController, DetailViewController ...
class MyUITableViewController : UITableViewController, DetailViewController ...
Then you inherit your view controllers from these view controllers, not the UIKit ones.
This is not natural either, but it doesn't force all your UIViewControllers to satisfy the UIViewControllerInject protocol as GoZoner suggested.

Related

Modeling an abstract base class in Swift

I have a Cocoa Touch class BaseViewController:
class BaseViewController: Named, UIViewController {
open var name = "Emma"
override func viewDidAppear() {
self.doSomethingImportant(self.name)
}
}
protocol Named {
var name: String
}
The intent behind BaseViewController is that all view controllers in my app will be derived from it, because it does something important in viewDidAppear() with name.
However, I'm trying to model this in a way where it'll be a compile-time error to subclass from BaseViewController without specifying name, and not have to supply a default name value in the base class. In other words:
Can I have BaseViewController require that its subclasses implement Named without it implementing Named itself?
If not, how else can I achieve this within the paradigm of Cocoa Touch plus Protocol-Oriented Programming?

Swift Protocol on a specific class?

I am building a UIPresentationController subclass. UIPresentationController defines an default initializer like this:
init(presentedViewController: UIViewController , presentingViewController: UIViewController?)
Now, in order for this to work, I want my presentedViewController to conform to some protocol, say MyRandomProtocol.
How can I re-write my initializer such that it takes the first argument as both a UIViewController subclass, and one that specifically conforms to MyRandomProtocol?
You can use generics.
init<T: UIViewController>(presentedViewController: T, ...) where T: MyRandomProtocol {
//initialization code
}

Can I use MCBrowserViewControllerDelegate with GameViewController class instead of ViewController class?

I don't think so. The error I receive states Type 'GameViewController' does not conform to protocol 'MCBrowserViewDelegate' https://developer.apple.com/library/prerelease/ios/documentation/MultipeerConnectivity/Reference/MCBrowserViewController_class/index.html
Assuming that GameViewController is a subclass of UIViewController, you certainly can since MCBrowserViewController is a subclass of UIViewController as well.
The error you are receiving is saying that you are not conforming to the delegate protocols required to use MCBrowserViewController. This means that in order to use a MCBrowserViewController, you first need to add MCBrowserViewDelegate to your class declaration similar to the following.
class GameViewController: UIViewController, MCBrowserViewDelegate {
You will also want to set your GameViewController to be the delegate within viewDidLoad or wherever you create it.
// create the MCBrowserViewController
let browserViewController = MCBrowserViewController(...)
browserViewController.delegate = self
self.presentViewController(browserViewController, animated: true, completion:nil)

Delegate property with different type in Swift

Ok so we have UIScrollView declaration:
protocol UIScrollViewDelegate: NSObjectProtocol { ... }
class UIScrollView: UIView {
...
weak var delegate: UIScrollViewDelegate?
...
}
And then UITableView with delegate variant?
protocol UITableViewDelegate: NSObjectProtocol, UIScrollViewDelegate { ... }
class UITableView: UIScrollView {
...
weak var delegate: UITableViewDelegate?
...
}
How Apple did this? When I do my
protocol MyScrollViewSubclassDelegate: NSObjectProtocol, UIScrollViewDelegate { ... }
class MyScrollViewSubclass: UIScrollView {
...
weak var delegate: MyScrollViewSubclassDelegate?
...
}
I get Property 'delegate' with type 'MyScrollViewSubclassDelegate?' cannot override a property with type 'UIScrollViewDelegate?'.
I stumbled upon this a few times and the only work-around I found was just calling my property something else like customDelegate or whatever you like.
It would be neat indeed to be able to just call it delegate but hey!
MyScrollViewSubclass has the delegate property of UIScrollView because it's subclass of UIScrollView.
As delegate is already defined by UIScrollView, you cannot define the same property name with a new type.
Change the variable name delegate to myDelegate (or something else) and it should work.
I got this working but I do not like the solution very much since it throws away type checking.
What I did was this. In my base class I declared the delegate as
weak var delegate: AnyObject? = nil
Then, when I want to call a method on the delegate I do
if let delegate = self.delegate as? MyBaseClassProtocol { delegate.myMethod() }
In my subclass I can then also do the same kind of thing
if let delegate = self.delegate as MySubclassProtocol { delegate.mySubclassMethod() }
As I say, it works, but I don't like it much. Throwing away the typechecking is not to be done lightly in my opinion. I am only sharing in the hope someone with stronger Swift skills can improve upon it, or correct it.

Define a variable which conforms to a protocol and inherits from a class in Swift [duplicate]

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.
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.
As of Swift 4, you can now do this.
Swift 4 implemented SE-0156 (Class and Subtype existentials).
The equivalent of this Objective-C syntax:
#property (strong, nonatomic) UIViewController<DetailViewController> * detailViewController;
Now looks like this in Swift 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.
Another way would be to introduce intermediate base classes for the appropriate UIKit view controllers that implement the protocol:
class MyUIViewControler : UIViewController, DetailViewController ...
class MyUITableViewController : UITableViewController, DetailViewController ...
Then you inherit your view controllers from these view controllers, not the UIKit ones.
This is not natural either, but it doesn't force all your UIViewControllers to satisfy the UIViewControllerInject protocol as GoZoner suggested.