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:
fun
I worked around this by borrowing from the swift runtime function unsafeBitCast
.
It's declared as func unsafeBitCast<T, U>(x: T, _: U.Type) -> U
and you can call it as unsafeBitCast(value, MyType)
.
Applied to your function this would be
func getArray<T : ROJSONObject>(key:String, _: T.Type) -> T[] {
// function stays the same
}
And you can call it like this
getArray("key", Document)
To answer the first part of your question
You need not add an additional parameter to the method to specify the type of T
as you already bat [T]
as return type
so you replace this line
object.getArray<Document>("key")
with this
object.getArray("key") as [Document]
This way you get an opportunity to specify the type to T
.
Working version of the code in the question ( second part )
• Init is required because a function returns a generic person Type (
newPerson(as person:T) -> T
)
• I've replaced the class methods func getWorkingHours()
by var workingHours { get }
.. It works equally, in a more 'swifty' way.
• getWorkingHours()
returns hours, as the name indicates, not a Person..
class Person {
required init() {}
var workingHours: Float { get { return 40 } }
}
class Boss : Person {
override var workingHours: Float { get { return 100 } }
}
class Worker : Person {
override var workingHours: Float { get { return 42 } }
}
func getWorkingHours<T : Person>(_ person: T) -> Float {
return person.workingHours
}
func newPerson<T : Person>(as person: T) -> T {
return T()
}
// -----------------------------------------------
let worker = Worker()
let boss = Boss()
print( getWorkingHours(worker) ) // prints 42.0
print( getWorkingHours(boss) ) // prints 100.0
let person = newPersonOfSameClass(as: worker)
print( getWorkingHours(person) ) // prints 42.0
Hope it helps.. This code is ready for copy/paste in playground.
You need to make initializer required
, then add let realType = T.self
line and replace T()
with realType()
.
class Person {
required 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 {
let realType = T.self
var person = realType()
person.getWorkingHours()
return person
}
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).
Don't call it like
object.getArray<Document>("key")
Instead, leave out the "<Document>" part, like this:
object.getArray("key")
Fixed the issue for me.