在Swift数组中以字符串形式存储和检索类类型,然后将泛型转换为已知的类字符串

时间:2019-02-25 18:27:33

标签: arrays swift generics

我将继续探索对Swift泛型的爱与恨,最后,我仍在努力克服一个我无法解决的基本缺陷:将泛型存储在数组中时(甚至使用fancy type erasure),在获得或设置数组属性之前,我仍然需要将数组中的结果值显式转换为已知类型。

我知道类型,但是似乎可以存储它的唯一方法是通过类的字符串名称(因为您似乎无法创建类型数组)。也许有一种适当的方式来编码/解码类型,以便可以将其存储在数组中?我尝试过NSClassFromString,但走得并不远。

这是一个说明挑战的游乐场:

enum Apple: String {
    case braeburn
    case macintosh
    case honeycrisp
}

protocol AppleProtocol {
    var brand: Apple { get set }
}

protocol AppleGetter {
    func getApple<T>(for key: Apple) -> T?
}

protocol PropertyReflectable { }

extension PropertyReflectable {
    subscript(key: String) -> Any? {
        let m = Mirror(reflecting: self)
        return m.children.first { $0.label == key }?.value
    }
}

struct GenericApple<T: Equatable>: AppleProtocol, Hashable {

    static func == (lhs: GenericApple<T>, rhs: GenericApple<T>) -> Bool {
        return lhs.brand == rhs.brand
    }

    var hashValue: Int { return brand.hashValue }

    var brand: Apple
    var generic: T

    init(brand: Apple, generic: T) {
        self.brand = brand
        self.generic = generic
    }
}

struct Apples {

    typealias Braeburn = GenericApple<Int>
    var braeburn = Braeburn(brand: .braeburn, generic: 10)

    typealias Honeycrisp = GenericApple<String>
    var honeycrisp = Honeycrisp(brand: .honeycrisp, generic: "A generic")
}

extension Apples: PropertyReflectable {
    func getApple<T>(for key: Apple, type: T.Type) -> T? {
        return self[key.rawValue] as? T
    }
}

这很好用!

var applesSet = Apples()

var braeburn = applesSet.getApple(for: Apple.braeburn, type: Apples.Braeburn.self)
braeburn?.generic = 14
print(braeburn?.generic)

但是,如果我想做什么:

struct AppleListElement {
    let brand: Apple
    let type: String
}

var apples = [AppleListElement]()
apples.append(AppleListElement(brand: .braeburn, type: "\(Apples.Braeburn.self)"))
apples.append(AppleListElement(brand: .honeycrisp, type: "\(Apples.Honeycrisp.self)"))

apples.forEach {
    applesSet.getApple(for: $0.brand, type: NSClassFromString($0.type))
}

0 个答案:

没有答案