Kamran
Kamran

Reputation: 15248

Creating classType from string to pass as concrete type to generic parameter Swift

I have protocol P, class A and B and my aim is to call generic method a<T: P>(_: T.Type) with class type parameter created from strings.

protocol P: class {
    static var p: String { get }
}

extension P {
    static var p: String { return String(describing: self) }
}

class A: P {

    func a<T: P>(_: T.Type) {
        print(T.p)
    }
}

class B: P {}

Below code works because forcefully casting to B.Type fixes the class type

let b = "B"
let type = NSClassFromString(b) as! B.Type
A().a(type)

But if lets say we have an array of class names without knowing their concrete types, how can we pass those?

["ClassA", "ClassB", "ClassC"].forEach({ className in
   let type = NSClassFromString(className) as! ????
   A().a(type)
})

Upvotes: 3

Views: 557

Answers (1)

OOPer
OOPer

Reputation: 47896

In Swift, type parameters in generic declarations needs to be solved at compile-time.

So, your ???? needs to be a concrete type conforming to P. But you cannot use any of the concrete types A.Type or B.Type as you describe.

And you may know you cannot use P.Type, as protocol P does not conform to P itself in Swift.


How about declaring the method a(_:) as non-generic?

class A: P {

    func a(_ type: P.Type) {
        print(type.p)
    }

}

["ModuleName.A", "ModuleName.B"].forEach({ className in
    let type = NSClassFromString(className) as! P.Type
        A().a(type)
})

You can pass class objects of type P.Type to the argument of type P.Type.

Upvotes: 2

Related Questions