Uczę się programowania na iOS z kursu online i za każdym razem, gdy tworzę niestandardowy widok (niestandardowa komórka widoku tabeli, komórka widoku kolekcji itp.), Instruktor zawsze implementuje ten inicjator:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Dlaczego właściwie zawsze muszę to nazywać? Co to robi? Czy mogę umieścić właściwości wewnątrz init?
NSCoding
, musisz zaimplementować ten inicjator, ponieważ jest to wymagane od klas, które implementująNSCoding
. Musisz przynajmniej wywołać metodę init nadklasy. JeśliNSCoder
zawiera zakodowane właściwości dla Twojej klasy, możesz użyć tej metody, aby je odzyskaćOdpowiedzi:
Zacznę od tej odpowiedzi w przeciwnym kierunku: co jeśli chcesz zapisać stan swojego widoku na dysku? Jest to znane jako serializacja . Odwrotna sytuacja to deserializacja - przywrócenie stanu obiektu z dysku.
NSCoding
Protokół określa dwa sposoby serializacji i odserializacji obiektów:Dlaczego więc jest potrzebny w Twojej klasie niestandardowej? Odpowiedzią jest Interface Builder. Po przeciągnięciu obiektu na scenorys i skonfigurowaniu go, Interface Builder serializuje stan tego obiektu na dysk, a następnie deserializuje go, gdy scenorys pojawia się na ekranie. Musisz powiedzieć Interface Builder, jak to zrobić. Przynajmniej, jeśli nie dodasz żadnych nowych właściwości do swojej podklasy, możesz po prostu poprosić superklasę o wykonanie pakowania i rozpakowywania za Ciebie, stąd
super.init(coder: aDecoder)
wezwanie. Jeśli Twoja podklasa jest bardziej złożona, musisz dodać własny kod serializacji i deserializacji dla podklasy.Jest to przeciwieństwo podejścia Visual Studio, które polega na zapisaniu kodu w ukrytym pliku w celu utworzenia obiektu w czasie wykonywania.
źródło
init(coder aCoder : NSCoder)
?awakeFromNib
nie zadziała.awakeFromNib
jest wywoływana w czasie wykonywania . Wszystko, co robisz w programie Interface Builder, ma miejsce podczas projektowania . Aby przenieść to, co zrobiłeś w czasie projektowania, do czasu uruchomienia, jestencodeWithCoder
(oszczędzanie) iinit(coder:)
(ładowanie)awakeFromNib
lubinitWIthFrame
Wymóg zaimplementowania tego inicjatora jest konsekwencją dwóch rzeczy:
Zasada substytucji Liskov . Jeśli S jest podklasą T (np.
MyViewController
Jest podklasąViewController
), to S obiektów (instancjiMyViewController
) musi mieć możliwość zastąpienia tam, gdzieViewController
oczekuje się T obiektów (instancji ).Inicjatory nie są dziedziczone w języku Swift, jeśli jakiekolwiek inicjatory są jawnie zdefiniowane w podklasie. Jeśli jeden inicjator jest jawnie podany, wszystkie inne muszą być jawnie podane (co może wtedy po prostu wywołać
super.init(...)
). Zobacz to pytanie dla uzasadnienia. Jest w Javie, ale nadal obowiązuje.W punkcie 1, wszystko, co
ViewController
może zrobić oryginał ,MyViewController
powinna być w stanie zrobić podklasa. Jedną z takich rzeczy jest możliwość inicjalizacji z danegoNSCoder
. W punkcie 2 twojaMyViewController
podklasa nie dziedziczy automatycznie tej zdolności. W związku z tym należy ręcznie podać inicjator, który spełnia to wymaganie. W takim przypadku wystarczy oddelegować zadanie do superklasy, aby zrobiła to, co zwykle.źródło