Ich versuche, ein Protokoll zu erstellen, das über eine statische Methode verfügt, die einen generischen Typ zurückgibt. In den meisten Fällen scheint das, was ich habe, einigermaßen gut zu funktionieren. Die Herausforderung kommt, wenn ich eine Erweiterung verwenden möchte, um diesen generischen Wert zurückzugeben. Hier ist was ich habe. Dieser Code kann auf einem Spielplatz platziert werden.Swift-Protokoll mit generischen Typen
Hier ist das erste Protokoll Ich möchte, die die associatedtype
protocol AWSerializable {
associatedtype T
static func deserialize(dictionary: [String : Any]) -> T?
func serialize() -> [String : Any]
}
enthält Dann habe ich ein anderes Protokoll erstellt, das mich Instanzen erstellen können, die die Wirkung von Deserialisieren tun:
protocol AWDeserializer {
func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T?
func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]?
}
Hier ist ein Beispiel das implementiert das AWSerializable
Protokoll glücklich:
class FooBar: AWSerializable {
typealias T = FooBar
var foo = ""
var bar = ""
static func deserialize(dictionary: [String : Any]) -> FooBar? {
let fooBar = FooBar()
fooBar.foo = (dictionary["foo"] as? String) ?? ""
fooBar.bar = (dictionary["bar"] as? String) ?? ""
return fooBar
}
func serialize() -> [String : Any] {
var serialized = [String : Any]()
serialized["foo"] = foo
serialized["bar"] = bar
return serialized
}
}
So weit so gut. Die Herausforderung kommt, wenn ich ein auf UserDefaults
erstellen möchte, um das Protokoll AWDeserializer
zu implementieren.
extension UserDefaults: AWDeserializer {
func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? {
if let serialized = UserDefaults.standard.object(forKey: key) as? [String : Any] {
return T.deserialize(dictionary: serialized)
}
return nil
}
func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? {
if let data = UserDefaults.standard.array(forKey: key) as? [[String : Any]] {
var values = [T]()
for entry in data {
if let value = T.deserialize(dictionary: entry) {
values.append(value)
}
}
return values
}
return nil
}
}
Das Problem hier ist mit T.deserialize(dictionary: serialized)
. Ich erhalte die folgende Fehlermeldung:
Dies wird durch die Anwendung der vorgeschlagenen Lösung leicht fixiert ist, oder vorzugsweise durch die Leitung zu return T.deserialize(dictionary: serialized) as? T
Ändern
Aber ich weiß nicht, wie die Tatsache, dass diese optionale Besetzung ist erforderlich, um damit zu beginnen. Gibt es eine Möglichkeit, die Protokolle zu definieren, für die diese Besetzung nicht erforderlich ist?
Dies ist eine Möglichkeit und Ich hatte das ursprünglich. Ich habe 2 Probleme bekommen. Der erste ist, dass ich dieses Protokoll nicht auf einer Erweiterung einer Klasse implementieren kann. Die "init" -Anforderung macht dies soweit ich weiß nicht möglich. Das andere Problem besteht darin, dass beim Erweitern einer Klasse die 'init'-Methode einige Nebenwirkungen mit erforderlichen Initialisierern in der Superklasse haben kann. – jervine10
Wenn ja, so? T' ist erforderlich, da 'AWSerializable.T' und' AWSerializable' unterschiedliche Typen sein können. Verwenden Sie diese Option, um 'AWSerializable.T' auf' AWSerializable' zu setzen. – beeth0ven
Ist das die einzige Möglichkeit, diese Protokolle zu deklarieren? Gibt es eine bessere Möglichkeit, 'AWDeserializer' zu deklarieren, so dass Cast nicht benötigt wird? – jervine10