knl
knl

Reputation: 1404

Instantiate an object of a generic type in Swift

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

Answers (4)

RY_ Zheng
RY_ Zheng

Reputation: 3427

  • used protocol to define the blueprint of init method;
  • other classes adopted this Initializable prototol have to implement init function
  • use function with generic type to create instance of a type
protocol 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

Morteza Soleimani
Morteza Soleimani

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

teradyl
teradyl

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

newacct
newacct

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

Related Questions