Reputation: 1404
I am implementing a class Foo
in Swift, that is supposed to instantiate objects of a given subclass of SuperBar
, e.g. Bar: SuperBar
. I really like generics in Swift, so I tried implementing it this way:
class Foo<T: SuperBar> {
func instantiateObject() -> T {
return T()
}
}
class SuperBar {
}
class Bar: SuperBar {
}
let foo = Foo<Bar>()
let obj = foo.instantiateObject()
You can run the code snippet in an Xcode Playground and observe that obj
is of type SuperBar
instead of Bar
, although it says Bar
when I Alt-click on the constant name.
Any Ideas? :)
Upvotes: 20
Views: 21768
Reputation: 3427
protocol
to define the blueprint of init
method;Initializable
prototol have to implement init
functiongeneric type
to create instance of a typeprotocol Initializable {
init()
}
class SuperBar : Initializable {
required init() {
print("init SuperBar")
}
}
class Bar : SuperBar {
required init() {
print("init Bar")
}
}
func createInstance<T>(type:T.Type) -> T where T:Initializable {
return type.init()
}
test:
let a = createInstance(type: SuperBar.self)
print("SuperBar: \(a.self)")
let b = createInstance(type: Bar.self)
print("Bar: \(b.self)")
result:
init SuperBar
SuperBar: __lldb_expr_22.SuperBar
init Bar
init SuperBar
Bar: __lldb_expr_22.Bar
Upvotes: 3
Reputation: 2670
Mark the class init as required
and then call init :
class SuperBar {
required init() {
}
}
class Foo<T: SuperBar> {
func instantiateObject() -> T {
return T.init()
}
}
Upvotes: 8
Reputation: 2802
You can force cast it if you know exactly the type of the generic.
let emptyObject:T = NSObject() as! T
Obviously this defeats the purpose of the generic class, but it can be useful for some default values or base class functionality as was in my case.
This is also dangerous and will crash if type T
is not NSObject
Upvotes: 1
Reputation: 122449
If you add required init() { }
to SuperBar
, it works correctly. That requirement should always be required anyway because you are creating an instance from an variable class.
The fact that it allows you to create it using an initializer that is not required is a bug.
Upvotes: 5