通用类类型不符合Any

时间:2018-01-12 12:32:48

标签: ios swift generics

我将通用类存储在数组中时遇到问题。我应该如何格式化我的数组的类型,同时保持对原始类型的引用(我知道我可以做var myClasses: [Any] = []但是从我的数组中检索变量时没有用处:(

示例如下:

import UIKit

protocol Reusable { }

extension UITableViewCell: Reusable { }
extension UICollectionViewCell: Reusable { }

class SomeClass<T> where T: Reusable {
    init() { }
}

var myClasses: [SomeClass<Reusable>] = []

myClasses.append(SomeClass<UITableViewCell>())
myClasses.append(SomeClass<UICollectionViewCell>())
myClasses.append(SomeClass<UITableViewCell>())
myClasses.append(SomeClass<UICollectionViewCell>())

编辑: 为了澄清,我使用了集合和表格单元格作为示例,我实际上并没有计划将它们存储在一起:)< / em>的

编辑2 var myClasses: [SomeClass<Reusable>] = []生成错误:using 'Reusable' as a concrete type conforming to protocol 'Reusable' is not supported

编辑3 var myClasses: [SomeClass<AnyObject>] = []生成错误:type 'AnyObject' does not conform to protocol 'Reusable'

4 个答案:

答案 0 :(得分:1)

我认为您可以创建某种可以接受和检索对象的Holder类:

class Holder {

    lazy var classes: [Any] = []

    func get<T>(_ type: T.Type) -> [T]? {
        return classes.filter({ $0 is T }) as? [T]
    }

}

主要部分:

let holder = Holder()
holder.classes.append(SomeClass<UITableViewCell>())

if let someTableViewCells = holder.get(SomeClass<UITableViewCell>.self)?.first {
    // or filter out again to get specific SomeClass of UITableViewCell
    print(someTableViewCells)
}  

或没有持有人类:

var classes: [Any] = []
classes.append(SomeClass<UITableViewCell>())

if let someTableViewCell = classes.filter({ $0 is SomeClass<UITableViewCell> }).first as? SomeClass<UITableViewCell> {
    print(someTableViewCell)
}

答案 1 :(得分:1)

我的建议是为您的SomeClass通用添加父协议SomeClass Container。然后在SomeClass中放入一个SomeClass对象数组。

protocol Reusable { func cakePlease() }

extension UITableViewCell: Reusable {
    func cakePlease() { }
}

extension UICollectionViewCell: Reusable {
    func cakePlease() { }
}

protocol SomeClassContainer { 
    func teaPlease()
    func afternoonPlease()
}

class SomeClass<T: Reusable>: SomeClassContainer {
    var item: T?

    init() { }

    func teaPlease() { }

    func afternoonPlease() {
        teaPlease()
        item?.cakePlease()
    }
}

var myClasses = [SomeClassContainer]()
myClasses.append(SomeClass<UITableViewCell>())
myClasses.append(SomeClass<UICollectionViewCell>())
myClasses.append(SomeClass<UITableViewCell>())
myClasses.append(SomeClass<UICollectionViewCell>())
myClasses[0].teaPlease()

if let item = (myClasses[0] as? SomeClass<UITableViewCell>)?.item {
    item.cakePlease()
}

for myClass in myClasses {
    if let tableCell = (myClass as? SomeClass<UITableViewCell>)?.item {
        tableCell.cakePlease()
    } else if let collectionCell = (myClass as SomeClass<UICollectionViewCell>)?.item {
        collectionCell.cakePlease()
    }
}

myClasses.forEach({ $0.afternoonPlease() })

答案 2 :(得分:1)

你应该在你的情况下使用AnyObject数组。因为你知道swift是强类型语言,例如

 SomeClass<UITableViewCell>

SomeClass<UICollectionViewCell>

是不同类型的对象。例如Array&lt; Int&gt;和数组&lt;字符串&gt;,它们都是数组,但它仍然是不同类型的对象。所以在这种情况下你必须使用声明:

var myClasses: [AnyObject] = []

并检查对象的类型,或在每次需要时对它们进行类型转换。

if (myClasses[0] is SomeClass<UICollectionViewCell>) { do something }

if let cell = myClasses[0] as? SomeClass<UICollectionViewCell> { do something }

答案 3 :(得分:0)

一般来说,键入阵列的方式是尽可能具体,同时仍覆盖所有基础。

我的意思是,例如存储UIViewController个对象的数组,即使每个对象实际上都是不同的类型。你不会在这里使用Any,因为你真的不需要那么一般。

在您的情况下,为什么不使用Reusable?因为无论如何你的所有通用类都符合它,它仍然是你可以去的一般,同时仍然保持方便。