Reputation: 12336
Consider a base UIViewController class...
class Rooms: UIViewController {
class func instantiate()->Rooms {
}
static func make()->Rooms {
let emplacedAndSetup = self.instantiate()
// various kodes here
// very likely put s.view somewhere
return emplacedAndSetup
}
sundryOtherFunctionality()
}
(Note the self.
before instantiate()
which seems to be necessary to get "that" instantiator.)
Each subclass knows its own storyboard ID to how use to instantiateViewController
:
class Dining: Rooms {
override class func instantiate()->Dining { // returns a "Dining"
let d = stbd.instantiateViewController(
withIdentifier: "Some Specific Scene") as! Dining
return d
}
}
class Bath: Rooms {
override class func instantiate()->Bath { // returns a "Bath"
let b = stbd.instantiateViewController(
withIdentifier: "Some Other Scene") as! Bath
return b
}
}
You can do this,
let d = Dining.make()
let r = Bath.make()
The only minor problem is, it returns the base class. BUT SEE BELOW. So in practice you have to
let d = Dining.make() as! Dining
let r = Bath.make() as! Bath
Is there a way to modify the static make
so that indeed Dining.make()
would return a Dining
and Bath.make()
would return a Bath
?
( @Hamish has pointed out that one could use an init
and Self
pattern, Method that returns object of type which was called from However, I think that's not possible due to the instantiateViewController
. )
So. Say you have code like
let d = Dining.make(blah blah)
in fact. At run time, d does become a "Dining", not a "Room"
that's fantastic.
But. If you do this in the IDE
let d:Dining = Dining.make(blah blah)
it fails - it thinks d is going to be a Room, not a Dining.
So all your code has to look like this:
let d = Dining.make(blah blah) as! Dining
which sucks. How to fix?
Note just TBC the solution is to make the static a generic, rather as in MartinR's answer here https://stackoverflow.com/a/33200426/294884 Example code in answer below.
Upvotes: 1
Views: 685
Reputation: 12336
I don't like to provide my own answer, but the solution is ..
So the problem is, at editor time
let d = Dining.make()
"doesn't work", you have to do this
let d = Dining.make() as! Dining
(It DOES work at compile time, d becomes a Dining: it doesn't "work" at editor time.)
So the solution is
static func make()->Rooms {
let emplacedAndSetup = self.instantiate()
return emplacedAndSetup
}
becomes
static func make<T: Rooms>()->T {
let emplacedAndSetup = self.instantiate() as! T
return emplacedAndSetup
}
So that's it.
Note - it's entirely possible AppzForLife
's solution works and/or is better as a general purpose "UIViewController auto-instantiator", but this is the answer to the question per se.
Upvotes: 2
Reputation: 59526
You can do something like this.
class RoomBase: RoomProtocol {
// things common to every room go here
required init() {}
}
You can put in
RoomBase
all the stuff you want the other rooms to inherit.
Next you put the make()
method into a protocol extension.
protocol RoomProtocol: class {
init()
}
extension RoomProtocol where Self: RoomBase {
static func make() -> Self {
let room = Self()
// set up
return room
}
}
Now you can write
class Dining: RoomBase {}
class Bath: RoomBase { }
And this code will work
let dining: Dining = Dining.make()
let bath: Bath = Bath.make()
Upvotes: 3