Сохранение и извлечение типа класса в виде строки в массиве Swift, а затем приведение общего к известной строке класса - PullRequest
0 голосов
/ 25 февраля 2019

Я продолжаю свое путешествие, чтобы обнаружить любовь и ненависть к дженерикам Swift, и в конце концов, я все еще борюсь с фундаментальным недостатком, который я не могу обойти: при хранении дженерика в массиве (дажес причудливым стиранием типа ) мне все еще нужно явно привести результирующее значение в массиве к известному типу, прежде чем я смогу получить или установить свойства в массиве.

Я знаю тип,но единственный способ сохранить его - это имя строки класса (так как кажется, что вы не можете создать массив типов).Может быть, есть правильный способ кодировать / декодировать тип, чтобы он мог храниться в массиве?Я пробовал с 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))
}
...