Chcę utworzyć klasę, która może przechowywać obiekty zgodne z określonym protokołem. Obiekty powinny być przechowywane w tablicy typu. Zgodnie z dokumentacją Swift protokoły mogą być używane jako typy:
Ponieważ jest to typ, możesz używać protokołu w wielu miejscach, w których dozwolone są inne typy, w tym:
- Jako typ parametru lub typ zwracany w funkcji, metodzie lub inicjatorze
- Jako typ stałej, zmiennej lub właściwości
- Jako typ elementów w tablicy, słowniku lub innym kontenerze
Jednak następujące generuje błędy kompilatora:
Protokół „SomeProtocol” może być używany tylko jako ograniczenie ogólne, ponieważ ma wymagania typu Self lub powiązane
Jak masz to rozwiązać:
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)
}
}
}
Odpowiedzi:
Trafiłeś w wariant problemu z protokołami w Swift, dla którego nie istnieje jeszcze dobre rozwiązanie.
Zobacz także Rozszerzanie tablicy, aby sprawdzić, czy jest posortowana w języku Swift? , zawiera sugestie, jak obejść ten problem, co może być odpowiednie dla konkretnego problemu (Twoje pytanie jest bardzo ogólne, być może możesz znaleźć obejście, korzystając z tych odpowiedzi).
źródło
Chcesz utworzyć klasę ogólną z ograniczeniem typu, które wymaga, aby klasy używane z nią były zgodne
SomeProtocol
, na przykład:źródło
SomeProtocol
-let protocolGroup: SomeClass<MyMemberClass> = SomeClass()
MyMemberClass
do tablicy?let foo = SomeClass<MyMemberClass>()
Equatable
zgodność - bez tego możesz użyć dokładnego kodu. Może zgłoś błąd / prośbę o funkcję?W Swift istnieje specjalna klasa protokołów, która nie zapewnia polimorfizmu w stosunku do typów, które go implementują. Takie protokoły używają
Self
lubassociatedtype
słów kluczowych w swoich definicjach (iEquatable
jest jednym z nich).W niektórych przypadkach można użyć opakowania z wymazaniem tekstu, aby nadać kolekcji homomorfizm. Poniżej przykład.
źródło
Ograniczone rozwiązanie, które znalazłem, polega na oznaczeniu protokołu jako protokołu tylko dla klasy. Umożliwi to porównywanie obiektów za pomocą operatora „===”. Rozumiem, że to nie zadziała w przypadku struktur itp., Ale w moim przypadku było wystarczająco dobre.
źródło
protocols
, jeśliaddElement
jest wywoływane więcej niż raz z tym samym obiektem?removeElement()
przed dołączeniem nowego elementu, jeśli chcesz uniknąć duplikatów.Rozwiązanie jest dość proste:
źródło
Equatable
protokół dziedziczył protokół. To robi ogromną różnicę.SomeProtocol
typem tablicy.Equatable
zgodność jest wymagana tylko do usuwania elementów z tablicy. Moje rozwiązanie jest ulepszoną wersją rozwiązania @almas, ponieważ może być używane z dowolnym typem Swift, który jest zgodny zEquatable
protokołem.Rozumiem, że twoim głównym celem jest przechowywanie kolekcji obiektów zgodnych z jakimś protokołem, dodawanie do tej kolekcji i usuwanie z niej. To jest funkcja określona w kliencie „SomeClass”. Dziedziczenie równoważne wymaga siebie, a to nie jest potrzebne do tej funkcji. Mogliśmy to zrobić w tablicach w Obj-C przy użyciu funkcji „index”, która może pobierać niestandardowy komparator, ale nie jest to obsługiwane w języku Swift. Zatem najprostszym rozwiązaniem jest użycie słownika zamiast tablicy, jak pokazano w kodzie poniżej. Udostępniłem metodę getElements (), która zwróci żądaną tablicę protokołów. Więc każdy, kto używa SomeClass, nie wiedziałby nawet, że do implementacji użyto słownika.
Ponieważ w każdym razie potrzebowałbyś jakiejś wyróżniającej właściwości, aby oddzielić swoje obiekty, założyłem, że jest to „nazwa”. Upewnij się, że do element.name = "foo" podczas tworzenia nowej instancji SomeProtocol. Jeśli nazwa nie jest ustawiona, nadal możesz utworzyć instancję, ale nie zostanie ona dodana do kolekcji, a metoda addElement () zwróci wartość „false”.
źródło
Znalazłem nie czysto rozwiązanie Swift w tym poście na blogu: http://blog.inferis.org/blog/2015/05/27/swift-an-array-of-protocols/
Sztuczka polega na dostosowaniu się do tego,
NSObjectProtocol
co wprowadzaisEqual()
. Dlatego zamiast używaćEquatable
protokołu i jego domyślnego użycia,==
możesz napisać własną funkcję, aby znaleźć element i go usunąć.Oto implementacja Twojej
find(array, element) -> Int?
funkcji:Uwaga: w tym przypadku obiekty zgodne z
SomeProtocol
must dziedziczą zNSObject
.źródło