Czy w języku Swift ktoś może wyjaśnić, jak zastąpić właściwość klasy nadrzędnej innym obiektem podklasy z właściwości oryginalnej?
Weźmy ten prosty przykład:
class Chassis {}
class RacingChassis : Chassis {}
class Car {
let chassis = Chassis()
}
class RaceCar: Car {
override let chassis = RacingChassis() //Error here
}
To daje błąd:
Cannot override with a stored property 'chassis'
Jeśli zamiast tego mam podwozie jako `` var '', pojawia się błąd:
Cannot override mutable property 'chassis' of type 'Chassis' with covariant type 'RacingChassis'
Jedyne, co udało mi się znaleźć w przewodniku w sekcji „Przesłanianie właściwości”, wskazuje, że musimy przesłonić metody pobierające i ustawiające, które mogą działać przy zmianie wartości właściwości (jeśli jest to „zmienna”), ale co ze zmianą klasy właściwości ?
strong
właściwością i otrzymywałem błąd podczas próby jej przesłonięcia - ale wygląda na to, że przeoczyłem, że przekłada się to na „niejawnie rozpakowany opcjonalny” (chassis!
) w Szybki, więcoverride var chassis : Chassis!
naprawia to.To wydaje się działać
źródło
let
wCar
klasie, która uniemożliwia zmianę. Możemy zmienićchassis
właściwość tylko wRaceCar
klasie.Spróbuj tego:
Następnie:
Szczegóły w http://www.mylonly.com/14957025459875.html
źródło
Dostarczony przez Solution Dash działa dobrze, z tym wyjątkiem, że superklasa musi być zadeklarowana za pomocą słowa kluczowego let, a nie var. Oto rozwiązanie, które jest możliwe, ale NIE ZALECANE!
Poniższe rozwiązanie skompiluje się z Xcode 6.2, SWIFT 1.1 (jeśli wszystkie klasy znajdują się w różnych plikach Swift), ale należy go unikać, ponieważ MOŻE PROWADZIĆ DO NIEOCZEKIWANYCH ZACHOWAŃ (W TYM AWARII, zwłaszcza przy użyciu typów nieobowiązkowych). UWAGA: TO NIE DZIAŁA Z XCODE 6.3 BETA 3, SWIFT 1.2
źródło
Teoretycznie możesz to zrobić w ten sposób ...
Działa to doskonale na placu zabaw Xcode.
Ale jeśli spróbujesz tego w prawdziwym projekcie, błąd kompilatora powie ci:
Sprawdziłem tylko Xcode 6.0 GM.
Niestety będziesz musiał poczekać, aż Apple to naprawi.
Przesłałem też raport o błędzie. 18518795
źródło
Widziałem wiele powodów, dla których projektowanie API przy użyciu zmiennych zamiast funkcji jest problematyczne, a używanie obliczonych właściwości wydaje mi się obejściem. Istnieją dobre powody, aby zachować hermetyzację zmiennych instancji. Tutaj stworzyłem protokół Samochód, z którym jest zgodny samochód. Ten protokół ma metodę akcesora, która zwraca obiekt Chassis. Ponieważ Car jest z nim zgodny, podklasa RaceCar może go zastąpić i zwrócić inną podklasę Chassis. Pozwala to klasie Car na programowanie w interfejsie (Automobile), a klasie RaceCar, która wie o RacingChassis, może uzyskać bezpośredni dostęp do zmiennej _racingChassis.
Innym przykładem załamania się projektowania interfejsu API przy użyciu zmiennych jest sytuacja, gdy w protokole są zmienne. Jeśli chcesz rozbić wszystkie funkcje protokołu na rozszerzenia, które możesz, z wyjątkiem tego, że przechowywane właściwości nie mogą być umieszczane w rozszerzeniach i muszą być zdefiniowane w klasie (aby to skompilować, musisz odkomentować kod w AdaptableViewController i usuń zmienną trybu z rozszerzenia):
Powyższy kod będzie miał następujący błąd kompilatora: „Rozszerzenia mogą nie mieć zapisanych właściwości”. Oto, jak możesz ponownie napisać powyższy przykład, aby wszystko w protokole można było oddzielić w rozszerzeniu za pomocą zamiast tego funkcji:
źródło
Możesz to osiągnąć za pomocą generyków:
Dzięki takiemu podejściu uzyskasz 100% bezpieczny kod bez wymuszonego rozpakowywania.
Ale to trochę hack i jeśli będziesz musiał przedefiniować kilka właściwości, to deklaracje klas będą wyglądać jak totalny bałagan. Więc bądź ostrożny z tym podejściem.
źródło
W zależności od tego, jak planujesz używać właściwości, najprostszym sposobem na to jest użycie opcjonalnego typu dla swojej podklasy i zastąpienie
didSet {}
metody super:Oczywiście musisz poświęcić trochę czasu na sprawdzenie, czy klasy można zainicjować w ten sposób, ale ustawiając właściwości na opcjonalne, chronisz się przed sytuacjami, w których rzutowanie już nie działa.
źródło
Możesz po prostu utworzyć inną zmienną RacingChassis.
źródło
chassis
i pozwalając nam pobrać / ustawić nasząRacingChassis
instancję zchassis
właściwością.Spróbuj tego:
źródło
źródło
Poniższe czynności umożliwiają użycie pojedynczego obiektu w klasach bazowych i pochodnych. W klasie pochodnej użyj właściwości obiektu pochodnego.
źródło
Niewielkie zróżnicowanie innych odpowiedzi, ale prostsze i bezpieczniejsze z kilkoma fajnymi zaletami.
Korzyści obejmują to, że nie ma ograniczeń co do tego, jakie musi być podwozie (var, let, opcjonalne itp.) I łatwo jest podklasować RaceCar. Podklasy RaceCar mogą wtedy mieć własną obliczoną wartość dla podwozia (lub podwozia wyścigowego).
źródło
wystarczy ustawić nową właściwość imageview z inną konwencją nazewnictwa, na przykład imgview, ponieważ imageView jest już własną własnością i nie możemy przypisać 2 silnych właściwości.
źródło