"array of classes that conform to a protocol" can be declared like Array<TheProtocol.Type>
.
You can:
var array: Array<ControllerConstructorProtocol.Type> = [
MyConstructor.self,
MyOtherConstructor.self,
]
But...,
array[0].construct()
// ^ error: accessing members of protocol type value 'ControllerConstructorProtocol.Type' is unimplemented
Calling method on the item is "unimplemented".
As of now, you have to declare the protocol as @objc
, and call the method via AnyClass
. Moreover, for some reasons, we cannot directly cast array[0]
to AnyClass
, instead, we have to cast it to Any
, then AnyClass
.
@objc protocol ControllerConstructorProtocol {
class func construct() -> UIViewController?
}
var array: Array<ControllerConstructorProtocol.Type> = [
MyConstructor.self,
MyOtherConstructor.self,
]
let vc = (array[0] as Any as AnyClass).construct()
Note: Casting problem was fixed in Swift 1.2 / Xcode 6.3. But "unimplemented" is "unimplmented" :(
Just random ideas:
It's depends on your actual use-case, but in this particular case, array of ()-> UIViewController?
closures is sufficient:
var array: [() -> UIViewController?] = [
MyConstructor.construct,
MyOtherConstructor.construct,
]
let vc = array[0]()
If you have several methods, you might want to use type-erased wrapper of the protocol.
protocol ControllerConstructorProtocol {
class func construct() -> UIViewController?
class func whoami() -> String
}
struct ControllerConstructorWrapper {
private let _construct: () -> UIViewController?
private let _whoami: () -> String
init<T: ControllerConstructorProtocol>(_ t:T.Type) {
_construct = { t.construct() }
_whoami = { t.whoami() }
}
func construct() -> UIViewController? { return _construct() }
func whoami() -> String { return _whoami() }
}
var array: [ControllerConstructorWrapper] = [
ControllerConstructorWrapper(MyConstructor),
ControllerConstructorWrapper(MyOtherConstructor),
]
let who = array[0].whoami()
let vc = array[0].construct()
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…