繁体   English   中英

声明符合协议的类数组

[英]Declare array of classes that conform to a protocol

让我们说我已经创建了这个协议和几个类

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运算符在(运行时)自行检查。

这是我尝试过没有成功:(

  1. 这会导致编译错误:

    '任何对象没有名为'construct'的成员

     var array = [ MyConstructor.self, MyOtherConstructor.self, ] var controller = array[0].construct() // << ERROR here 
  2. 写这个更糟糕,因为类本身不符合协议(他们的实例)

    类型'MyConstructor.Type'不符合协议'ControllerConstructorProtocol'

     var array: Array<ControllerConstructorProtocol> = [ MyConstructor.self, // << ERROR here MyOtherConstructor.self, ] 

编辑2016/04/23 :在Swift 2.2(Xcode 7.3)中,可以编写@ rintaro的原创想法 :)

let array: Array<ControllerConstructorProtocol.Type> = [
    MyConstructor.self,
    MyOtherConstructor.self,
]
let viewController = array[0].construct()

“符合协议的类数组”可以声明为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?数组()-> 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()

尝试这个:

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()
    }
}

另一个解决方案,虽然不是很漂亮......

不确定我是否完全接受了你的问题,但为什么不这样做:

var array: [ControllerConstructorProtocol] = [MyConstructor(), MyOtherConstructor()]

如果你真的只想要使用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 { ... }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM