Я продолжаю свое путешествие, чтобы обнаружить любовь и ненависть к дженерикам 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))
}