TL;DR
I'm looking for an array type (var array = [TheTypeImLookingFor]()
) like 'all objects that subclasses UIViewController
and implements the protocol MyProtocol
.
Explanation
I'm building a kind of wizard view with a container view and embedded child views (controller). No problem, this will work as long, as I have only one base
type of child view controllers.
Due to the content of screens, I have now a bunch of view controllers of type MyTableViewController
which is a subclass of UITableViewController
and other view controllers that have regular UIViewControllers
as base.
All of the view controllers have one thing in common. A default data property myData: MyObject
.
I created a protocol MyProtocol
that contains this property.
Now, I have to combine all this view controllers into one array to use it as wizard steps. As long as I only have to access the view controller methods (array items are type of UIViewController
) I'm able to use var viewControllers = [UIViewController]()
or if I wanna only access the myData
property, I change the array item type to MyObject
.
But the problem is, I have to access the methods from the UIViewController
and from the protocol.
That's why I'm looking for an array type like 'all objects that subclasses UIViewController
and implements the protocol MyProtocol
.
I tried:
var viewControllers = [UIViewController: MyProtocol]()
// is a dict- `var viewControllers = UIViewController where MyProtocol
- `var viewControllers = UIViewController.conforms(to: MyProtocol)
- ...
But nothing works as expected.
You could use protocol composition with a placeholder protocol for the class:
This covers the type safety part but doesn't let you access UIViewController methods without type casting. You can reduce the type casting ugliness by adding a typed property to your protocol (when it applies to the base class)
Alternatively, you could define the UIViewController methods you need to call in the placeholder protocol but that could quickly become tiresome and redundant if you're going to use many of them.
I had a similar issue and solved it with a custom base class. Imagine an array like:
which all should extend from
UIViewController
and implement the following protocol:Then I've declared a base class like:
Caution: this class doesn't implement the above protocol but holds a property which provides the desired functionality. The next step is to define one of the
UIViewController
that will be added to the array:The important part is located in the viewDidLoad method. The view controller assigns itself as the delegate.
Usage:
The benefits:
MapViewController
is like an abstract class and If I change the MapViewControllerDelegate the compiler forces me to implement the changes in theGoogleMapsViewController
and in theMapboxMapsViewController
.UIViewController
is still aUIViewController
and provides all its methods.You can also create a
protocol
that defines all theUIViewController
functions that you need. Make sure that you copy the method signature, otherwise you will have to implement the functions again.Then, you can extend your existing protocol.
Or create a new protocol that extends
UIViewControllerInteractions
andMyProtocol
.Now, when you extend your
SubclassUIViewController
, you still only have to add yourmyData
because the methods in theUIViewControllerInteractions
are already implemented byUIViewController
(that's why we copied the method signature)You can now have an
array
ofMyProtocol
orMyProtocolViewController
and also call the methods defined inUIViewControllerInteractions
which will call theUIViewController
methods.Why not simply create :
Why not creating :
As far as I know, there's currently no way to type something so that it describes anything which inherits from a given class and conforms to a given protocol.
One possible hacky workaround would be to just create a wrapper type in order to perform typecasting for you in the case that you need to treat the instance as a
MyProtocol
.Now you can create a
[MyProtocolViewController]
, and can either treat an element as aUIViewController
, or aMyProtocol
.