让我们说我已经创建了这个协议和几个类
import UIKit
protocol ControllerConstructorProtocol {
class func construct() -> UIViewController?
}
class MyConstructor: ControllerConstructorProtocol {
class func construct() -> UIViewController? {
return UIViewController()
}
}
class MyOtherConstructor: ControllerConstructorProtocol {
class func construct() -> UIViewController? {
return UITableViewController(style: .Grouped)
}
}
现在我想声明一个包含符合此类协议的对象类的数组。
我怎么声明呢?理想情况下,我希望编译器检查数组是否正确填充(在编译时),而不是使用as
运算符在(运行时)自行检查。
这是我尝试过的但没有成功:(
这会导致编译错误:
'任何对象没有名为'construct'的成员
var array = [
MyConstructor.self,
MyOtherConstructor.self,
]
var controller = array[0].construct() // << ERROR here
写这个更糟糕,因为类本身不符合 协议(他们的实例)
类型'MyConstructor.Type'不符合协议 'ControllerConstructorProtocol'
var array: Array<ControllerConstructorProtocol> = [
MyConstructor.self, // << ERROR here
MyOtherConstructor.self,
]
编辑2016/04/23 :在Swift 2.2(Xcode 7.3)中,可以编写@rintaro's original idea:)
let array: Array<ControllerConstructorProtocol.Type> = [
MyConstructor.self,
MyOtherConstructor.self,
]
let viewController = array[0].construct()
答案 0 :(得分:9)
“符合协议的类数组”可以声明为Array<TheProtocol.Type>
。
你可以:
var array: Array<ControllerConstructorProtocol.Type> = [
MyConstructor.self,
MyOtherConstructor.self,
]
但是...,
array[0].construct()
// ^ error: accessing members of protocol type value 'ControllerConstructorProtocol.Type' is unimplemented
项目的调用方法是“未实现的”。
截至目前,您必须将协议声明为@objc
,并通过AnyClass
调用该方法。此外,由于某些原因,我们无法直接将array[0]
转换为AnyClass
,而是必须将其转换为Any
,然后转换为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()
注意:在Swift 1.2 / Xcode 6.3中修复了转换问题。但“未实现”是“未实现的”:(
随意的想法:
这取决于您的实际用例,但在这种特殊情况下,()-> UIViewController?
闭包数组就足够了:
var array: [() -> UIViewController?] = [
MyConstructor.construct,
MyOtherConstructor.construct,
]
let vc = array[0]()
如果您有多种方法,则可能需要使用协议的类型擦除包装。
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()
答案 1 :(得分:0)
试试这个:
var myConst = MyConstructor()
var myOthConst = MyOtherConstructor()
var array:[AnyObject] = [
myConst,
myOthConst
]
for a in array
{
if a is MyConstructor
{
println("a is type of MyConstructor")
(a as! MyConstructor).myMethod()
}
else if a is MyOtherConstructor
{
println("a is type of MyOtherConstructor")
(a as! MyOtherConstructor).myMethod()
}
}
另一种解决方案,虽然不是那么漂亮......
答案 2 :(得分:0)
不确定我是否完全接受了您的问题,但为什么不这样:
var array: [ControllerConstructorProtocol] = [MyConstructor(), MyOtherConstructor()]
答案 3 :(得分:0)
如果你真的只想要使用sotre类(符合协议)那么你可以通过以下方式实现(在Swift 3中):
如果要使用协议类型创建新实例,则必须将init()添加到协议声明中:
protocol SomeProtocol: ConformsToOtherProtocolIfNeeded {
init(...) { ... }
func someFunction(...) { ... }
}
class Class1: SomeProtocol {
init(...) { ... }
func someFunction(...) { ... }
}
class Class2: SomeProtocol {
init(...) { ... }
func someFunction(...) { ... }
}
声明数组(如上所述):
var someProtocols: Array<SomeProtocol.Type> = [
Class1.self,
Class2.self,
]
如果你想使用someFunction,你必须创建一个实例,因为数组中的元素不是实例。 例如:
for sp in someProtocols {
let instance = sp.init()
instance.someFunction()
}
如果要比较类的类型,还必须创建实例。 (所以你不能直接使用数组项( sp )。)
示例:
if type(of: instance) == type(of: otherInstance) { ... }
if instance is SomeProtocol { ... }
if instance is Class1 { ... }