In my application I want to create an generic method which creates an array of object depening on the given type T.
I created the following function:
func getArray<T : ROJSONObject>(key:String) -> T[] {
var elements = T[]()
for jsonValue in getValue(key).array! {
var element = T()
element.jsonData = jsonValue
elements.append(element)
}
return elements
}
Now I want to pass the type when I call the method, so it does know which type it should create internally. I think in Java and C# you can use a method like that:
object.getArray<Document>("key")
When I call it like that, I always get the error:
Cannot explicitly specialize a generic function
So my fix was to define an additional parameter containing an instance of the type T so it does automatically detect the type:
func getArray<T : ROJSONObject>(key:String, type:T) -> T[] {
var elements = T[]()
for jsonValue in getValue(key).array! {
var element = T()
element.jsonData = jsonValue
elements.append(element)
}
return elements
}
Is there really no other way to get that behaviour without passing an unused instance? Or am I misunterstanding something?
Further Testing
After the answer of jtbandes I did some more testing. I tried to force the Type by adding the as
in the call.
class Person {
init() { }
func getWorkingHours() -> Float {
return 40.0
}
}
class Boss : Person {
override func getWorkingHours() -> Float {
println(100.0)
return 100.0
}
}
class Worker : Person {
override func getWorkingHours() -> Float {
println(42.0)
return 42.0
}
}
func getWorkingHours<T : Person>() -> T {
var person = T()
person.getWorkingHours()
return person
}
var worker:Worker = getWorkingHours() as Worker
var boss:Boss = getWorkingHours() as Boss
worker.getWorkingHours() // prints out 40.0 instead of 42.0
boss.getWorkingHours() // prints out 40.0 instead of 100.0
So somehow the type is always the base type even I've specified the type with the as
keyword. I know the example does not make much sense, but it was just for testing purpose..
I think it is a bug.
You can work around it by making the class a sub-class of NSObject
or mark constructor of base class with @required
import Cocoa
class A : NSObject {
init() { }
}
class B : A {}
class C : A {}
func Create<T:NSObject> () -> T {
return T()
}
println(Create() as A)
println(Create() as B)
println(Create() as C)
//<_TtC11lldb_expr_01A: 0x7f85ab717bc0>
//<_TtC11lldb_expr_01B: 0x7f85ab451e00>
//<_TtC11lldb_expr_01C: 0x7f85ab509160>
class D {
@required init() { }
}
class E : D {
init() { }
}
class F : D {
init() { }
}
func Create2<T:D> () -> T {
return T()
}
println(Create2() as D)
println(Create2() as E)
println(Create2() as F)
//C11lldb_expr_01D (has 0 children)
//C11lldb_expr_01E (has 1 child)
//C11lldb_expr_01F (has 1 child)
Not sure why @required
solve the problem. But this is the reference
required
Apply this attribute to a designated or convenience initializer of a class to indicate that every subclass must implement that initializer.
Required designated initializers must be implemented explicitly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or when the subclass overrides the designated initializers with convenience initializers).
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments