How would one go about assigning an instance of a class which can have a generic type, but you don't know what type that is until run time?
For example.
We have a protocol and enums that conform to it like this:
protocol Stage: CaseIterable, Hashable {
var fooBarLength: Int { get }
}
enum FirstStage: String, Stage {
var fooBarLength: Int { 10 }
case section1
case section2
}
enum SecondStage: String, Stage {
var fooBarLength: Int { 10 }
case section1
case section2
case section3
}
Next we have some kind of controller that uses the protocol as a generic type... comme ça...
class FooBarController<StageType: Stage>: UIViewController {
private var stages: [StageType: Float] = [:]
}
Then used like this:
func fooBarScreen(boop: SomethingThatKnowsAboutTheStages) {
var fooBarController: FooBarController // <---- how do I define this????
if boop.someCondition() {
fooBarController = FooBarController<FirstStage>()
} else {
fooBarController = FooBarController<SecondStage>()
}
}
In Java / Kotlin I could just do this as it is above, how do I achieve the same thing in Swift?
Currently I get
"Reference to generic type 'FooBarController' requires arguments in <...>"
Secondary Question
Is there a more generic way than having to use that if-statement here? Ideally I would like the fooBarScreen
method to not care about the generic type and just have SomethingThatKnowsAboutTheStages
provide the type for me.
CodePudding user response:
You can specify a protocol for providing Stage
types like so:
protocol StageProvider {
associatedtype T: Stage
func getType() -> T.Type
}
Then make your SomethingThatKnowsAboutTheStages
or any other one conform this protocol:
class SomethingThatKnowsAboutTheStages: StageProvider {
typealias T = SecondStage
func getType() -> T.Type {
SecondStage.self
}
}
Add an initializer for your FooBarController
:
class FooBarController<StageType: Stage>: UIViewController {
convenience init(stage: StageType.Type) {
self.init()
}
}
And finally use all these:
func fooBarScreen<T: StageProvider>(boop: T) {
let controller = FooBarController(stage: boop.getType())
}