Ich möchte eine Klasse erstellen, die Objekte speichern kann, die einem bestimmten Protokoll entsprechen. Die Objekte sollten in einem typisierten Array gespeichert werden. Gemäß der Swift-Dokumentation können Protokolle als Typen verwendet werden:
Da es sich um einen Typ handelt, können Sie ein Protokoll an vielen Stellen verwenden, an denen andere Typen zulässig sind, einschließlich:
- Als Parametertyp oder Rückgabetyp in einer Funktion, Methode oder einem Initialisierer
- Als Typ einer Konstante, Variablen oder Eigenschaft
- Als Elementtyp in einem Array, Wörterbuch oder einem anderen Container
Folgendes erzeugt jedoch Compilerfehler:
Das Protokoll 'SomeProtocol' kann nur als generische Einschränkung verwendet werden, da es Self- oder zugehörige Typanforderungen hat
Wie soll man das lösen:
protocol SomeProtocol: Equatable {
func bla()
}
class SomeClass {
var protocols = [SomeProtocol]()
func addElement(element: SomeProtocol) {
self.protocols.append(element)
}
func removeElement(element: SomeProtocol) {
if let index = find(self.protocols, element) {
self.protocols.removeAtIndex(index)
}
}
}
Antworten:
Sie haben eine Variante eines Problems mit Protokollen in Swift gefunden, für die es noch keine gute Lösung gibt.
Siehe auch Array erweitern, um zu überprüfen, ob es in Swift? Sortiert ist. Es enthält Vorschläge zur Umgehung des Problems, die für Ihr spezifisches Problem geeignet sein können (Ihre Frage ist sehr allgemein gehalten. Vielleicht können Sie anhand dieser Antworten eine Problemumgehung finden).
quelle
Sie möchten eine generische Klasse mit einer Typeinschränkung erstellen, für die die verwendeten Klassen den folgenden Anforderungen entsprechen
SomeProtocol
:quelle
SomeProtocol
-let protocolGroup: SomeClass<MyMemberClass> = SomeClass()
MyMemberClass
dem Array nur Objekte der Klasse hinzufügen ?let foo = SomeClass<MyMemberClass>()
Equatable
Konformität - ohne diese können Sie Ihren genauen Code verwenden. Möglicherweise eine Fehler- / Funktionsanfrage einreichen?In Swift gibt es eine spezielle Klasse von Protokollen, die keinen Polymorphismus gegenüber den Typen bieten, die sie implementieren. Solche Protokolle verwenden
Self
oderassociatedtype
Schlüsselwörter in ihren Definitionen (undEquatable
sind eines davon).In einigen Fällen ist es möglich, einen vom Typ gelöschten Wrapper zu verwenden, um Ihre Sammlung homomorph zu machen. Unten ist ein Beispiel.
quelle
Die begrenzte Lösung, die ich gefunden habe, besteht darin, das Protokoll als Nur-Klasse-Protokoll zu markieren. Auf diese Weise können Sie Objekte mit dem Operator '===' vergleichen. Ich verstehe, dass dies für Strukturen usw. nicht funktioniert, aber es war in meinem Fall gut genug.
quelle
protocols
, wennaddElement
mehr als einmal mit demselben Objekt aufgerufen wird?removeElement()
vor dem Anhängen des neuen Elements aufrufen, wenn Sie Duplikate vermeiden möchten.Die Lösung ist ziemlich einfach:
quelle
Equatable
. Es macht einen großen Unterschied.SomeProtocol
in einem typisierten Array speichern .Equatable
Konformität ist nur zum Entfernen von Elementen aus dem Array erforderlich. Meine Lösung ist eine verbesserte Version der @ almas-Lösung, da sie mit jedem Swift-Typ verwendet werden kann, der demEquatable
Protokoll entspricht .Ich gehe davon aus, dass Ihr Hauptziel darin besteht, eine Sammlung von Objekten zu halten, die einem Protokoll entsprechen, diese Sammlung zu ergänzen und daraus zu löschen. Dies ist die in Ihrem Client angegebene Funktion "SomeClass". Gleichwertige Vererbung erfordert Selbst und das wird für diese Funktionalität nicht benötigt. Wir hätten diese Funktion in Arrays in Obj-C mithilfe der "Index" -Funktion ausführen können, die einen benutzerdefinierten Komparator verwenden kann, dies wird jedoch in Swift nicht unterstützt. Die einfachste Lösung besteht also darin, ein Wörterbuch anstelle eines Arrays zu verwenden, wie im folgenden Code gezeigt. Ich habe getElements () bereitgestellt, mit dem Sie das gewünschte Protokollarray zurückgeben können. Jeder, der SomeClass verwendet, würde also nicht einmal wissen, dass ein Wörterbuch für die Implementierung verwendet wurde.
Da Sie in jedem Fall eine unterscheidende Eigenschaft benötigen würden, um Ihre Objekte zu trennen, habe ich angenommen, dass es sich um "Name" handelt. Stellen Sie sicher, dass do element.name = "foo" ist, wenn Sie eine neue SomeProtocol-Instanz erstellen. Wenn der Name nicht festgelegt ist, können Sie die Instanz weiterhin erstellen, sie wird jedoch nicht zur Auflistung hinzugefügt, und addElement () gibt "false" zurück.
quelle
Ich habe in diesem Blog-Beitrag eine nicht reine Swift-Lösung gefunden: http://blog.inferis.org/blog/2015/05/27/swift-an-array-of-protocols/
Der Trick besteht darin, sich an
NSObjectProtocol
die Einführung anzupassenisEqual()
. Anstatt dasEquatable
Protokoll und seine Standardverwendung zu verwenden, können==
Sie daher eine eigene Funktion schreiben, um das Element zu finden und es zu entfernen.Hier ist die Implementierung Ihrer
find(array, element) -> Int?
Funktion:Hinweis: In diesem Fall müssen Ihre konformen Objekte von
SomeProtocol
erbenNSObject
.quelle