Czy istnieje sposób na stworzenie abstrakcyjnej klasy w Swift Language, czy jest to ograniczenie, tak jak Objective-C? Chciałbym stworzyć klasę abstrakcyjną porównywalną z tym, co Java definiuje jako klasę abstrakcyjną.
141
Czy istnieje sposób na stworzenie abstrakcyjnej klasy w Swift Language, czy jest to ograniczenie, tak jak Objective-C? Chciałbym stworzyć klasę abstrakcyjną porównywalną z tym, co Java definiuje jako klasę abstrakcyjną.
Odpowiedzi:
W Swift nie ma abstrakcyjnych klas (podobnie jak Objective-C). Najlepszym rozwiązaniem będzie użycie protokołu , który jest podobny do interfejsu Java.
Dzięki Swift 2.0 możesz następnie dodawać implementacje metod i implementacje obliczonych właściwości przy użyciu rozszerzeń protokołów. Jedynymi ograniczeniami jest to, że nie możesz podać zmiennych składowych ani stałych i nie ma dynamicznego wysyłania .
Przykładem tej techniki byłoby:
Zauważ, że zapewnia to funkcje podobne do "klas abstrakcyjnych" nawet dla struktur, ale klasy mogą również implementować ten sam protokół.
Zauważ również, że każda klasa lub struktura, która implementuje protokół Employee, będzie musiała ponownie zadeklarować właściwość AnnualSalary.
Co najważniejsze, zauważ, że nie ma dynamicznej wysyłki . Gdy
logSalary
jest wywoływana dla wystąpienia, które jest przechowywane jako aSoftwareEngineer
, wywołuje zastąpioną wersję metody. GdylogSalary
jest wywoływana na instancji po jej rzutowaniu na plikEmployee
, wywołuje oryginalną implementację (nie jest dynamicznie wysyłana do nadpisanej wersji, mimo że instancja jest faktycznie plikiemSoftware Engineer
.Aby uzyskać więcej informacji, obejrzyj świetny film WWDC dotyczący tej funkcji: Tworzenie lepszych aplikacji z typami wartości w języku Swift
źródło
protocol Animal { var property : Int { get set } }
. Możesz również pominąć set, jeśli nie chcesz, aby obiekt miał seterafunc logSalary()
do deklaracji protokołu pracownika, przykład zostanie wydrukowanyoverridden
dla obu wywołań funkcjilogSalary()
. To jest w Swift 3.1. W ten sposób uzyskujesz korzyści z polimorfizmu. W obu przypadkach wywoływana jest właściwa metoda.Zwróć uwagę, że ta odpowiedź jest skierowana do Swift 2.0 i nowszych wersji
To samo zachowanie można osiągnąć dzięki protokołom i rozszerzeniom protokołów.
Najpierw piszesz protokół, który działa jako interfejs dla wszystkich metod, które muszą być zaimplementowane we wszystkich typach, które są z nim zgodne.
Następnie możesz dodać domyślne zachowanie do wszystkich typów, które są z nim zgodne
Możesz teraz tworzyć nowe typy, implementując
Drivable
.W zasadzie otrzymujesz:
Drivable
są implementowanespeed
Drivable
(accelerate
)Drivable
jest gwarantowane, że nie zostanie utworzony, ponieważ jest to tylko protokółTen model w rzeczywistości zachowuje się znacznie bardziej jak cechy, co oznacza, że możesz dostosować się do wielu protokołów i przyjąć domyślne implementacje dowolnego z nich, podczas gdy w przypadku abstrakcyjnej nadklasy ogranicza się do prostej hierarchii klas.
źródło
UICollectionViewDatasource
. Chciałbym usunąć cały standardowy szablon i zamknąć go w osobnym protokole / rozszerzeniu, a następnie ponownie wykorzystać przez wiele klas. W rzeczywistości wzór szablonu byłby tutaj idealny, ale ...Myślę, że jest to najbliższe Java
abstract
lub C #abstract
:Zauważ, że aby
private
modyfikatory działały, musisz zdefiniować tę klasę w osobnym pliku Swift.EDYCJA: Mimo to ten kod nie pozwala na zadeklarowanie metody abstrakcyjnej i tym samym wymusza jej implementację.
źródło
Najprostszym sposobem jest użycie wywołania
fatalError("Not Implemented")
metody abstrakcyjnej (nie zmiennej) w rozszerzeniu protokołu.źródło
(MyConcreteClass() as MyInterface).myMethod()
ale zadziała ! Klucz jest zawartymyMethod
w deklaracji protokołu; w przeciwnym razie połączenie zawiesza się.Po kilku tygodniach zmagań w końcu zrozumiałem, jak przetłumaczyć abstrakcyjną klasę Java / PHP na Swift:
Jednak myślę, że Apple nie zaimplementował klas abstrakcyjnych, ponieważ zazwyczaj używa zamiast tego wzorca delegat + protokół. Na przykład ten sam wzór powyżej byłby lepiej wykonany w ten sposób:
Potrzebowałem tego rodzaju wzorca, ponieważ chciałem ujednolicić niektóre metody w UITableViewController, takie jak viewWillAppear itp. Czy to było pomocne?
źródło
Istnieje sposób na symulowanie klas abstrakcyjnych przy użyciu protokołów. To jest przykład:
źródło
Jeszcze jednym sposobem implementacji klasy abstrakcyjnej jest blokowanie inicjatora. Zrobiłem to w ten sposób:
źródło
Próbowałem stworzyć
Weather
abstrakcyjną klasę, ale używanie protokołów nie było idealne, ponieważ musiałem ciągle pisać te sameinit
metody. Rozszerzenie protokołu i napisanieinit
metody sprawiało pewne problemy, zwłaszcza że korzystałem zNSObject
complianceNSCoding
.Więc wymyśliłem to dla
NSCoding
zgodności:Co do
init
:źródło
Przenieś wszystkie odwołania do abstrakcyjnych właściwości i metod klasy Base do implementacji rozszerzenia protokołu, gdzie samoograniczenie do klasy podstawowej. Uzyskasz dostęp do wszystkich metod i właściwości klasy Base. Dodatkowo kompilator sprawdza implementację metod abstrakcyjnych i właściwości w protokole dla klas pochodnych
źródło
Z ograniczeniem braku dynamicznej wysyłki, możesz zrobić coś takiego:
źródło