代码之家  ›  专栏  ›  技术社区  ›  brandonscript

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

  •  0
  • brandonscript  · 技术社区  · 7 年前

    我将继续我的旅程,去发现人们对斯威夫特仿制药的爱与恨,最终,我仍在努力克服一个根本性的缺陷:在数组中存储仿制药时(即使使用 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 回复  |  直到 7 年前