2009-04-13 12 views
16

Mam UITableViewController podklasę, która jest instancję, w zależności od tego, gdzie jest to stosowane, w NIB lub za pomocą kodu. W obu przypadkach chcę dokonać personalizacji w metodzie inicjalizującej. Czy to znaczy, że trzeba zaimplementować zarówno initWithNibName:bundle:iinitWithCoder: i nazwałbym każdy sposób jej odpowiedni super-inicjator?Która inicjatora (ów) przesłonić dla UITableViewController podklasy

Chociaż teraz nie potrzebuję tego, co zrobić, jeśli chcę mieć możliwość utworzenia instancji kontrolera widoku za pomocą initWithStyle:? Czy potrzebowałbym 3 różnych metod inicjowania, które powielałyby to samo zachowanie?

Wydaje się, że to narusza konwencję cały wyznaczony inicjalizator, ponieważ nie byłaby zasadniczo 3 oddzielne inicjalizatory że nie kończy się wywołaniem wspólną metodę init. A może istnieje sposób na stworzenie wspólnego inicjalizatora z 3 różnymi ścieżkami?

Odpowiedz

11

Moja dezorientacja została oparta na błędnym przekonaniu, że każda klasa powinna mieć jeden wyznaczony inicjatora. To nie jest prawda, a w przypadku UITableViewController istnieją 3 wyznaczone inicjalizatory (o ile mogę powiedzieć):

  1. initWithStyle: zadeklarowana lokalnie
  2. initWithNibName:bundle: odziedziczone UIViewController
  3. initWithCoder: od przyjęcia protokołu NSCoding

trzeba zastąpić 1 lub więcej z nich w Twojej podklasie, w zależności od tego, jak twoja podklasa zostaje utworzona. W moim przypadku musiałem zaimplementować # 2 i # 3, ponieważ klasa może być ładowana z NIB lub tworzona przez kod z odniesieniem do NIB. (I sobie wyobrazić, że to rzadkie, że będziesz używać zarówno initWithStyle: i initWithNibName:bundle: do jednej klasy).

znalazłem Apple Coding Guidelines for Cocoa pomocne.

+0

To nie jest dokładne. - [UIViewController initWithCoder:] wydaje się wywoływać - [UIViewController initWithNibName: bundle:]. Nie trzeba go przesłonić. Postępuj zgodnie z radą KennyTM. – fnf

+0

jest dokładne. Mam sytuację, w której wywoływany jest tylko initWithCoder. (Mam zastąpione wszystkie 3 metody). – Sam

+0

Co jest naprawdę mylące na iOS8 to, że initWithStyle: wywołuje initWithNibName: bundle: i oba muszą być zadeklarowane jako wyznaczone inicjatory. Nie jest to zgodne z szybkimi regułami inicjalizatora. W systemie iOS 8, jeśli nie zdefiniujesz initWithNibName: bundle: i wywołaj initWithStyle :, aplikacja ulega awarii. Zostało to naprawione na iOS9. –

0

Wdrożenie:

- (void) viewDidLoad 

i zrobić tam swój inicjalizacji komponentu.

Ma tę zaletę, tylko robi inicjalizacji gdy widok jest rzeczywiście wymagane.

Albo po prostu zrobić oddzielną metodę konfiguracji wywoływana przez wszystkie inicjalizatorów.

+0

Nie mogę korzystać viewDidLoad ponieważ konkretnie muszę założyć self.navigationItem, które mogą być wykorzystane przed widok jest załadowany . Mogłem stworzyć osobną metodę konfiguracji. Czy to jest po prostu, że NSCoding jest zasadniczo wyjątkiem od zasady "single designeser"? –

2

W celu wyjaśnienia, initWithStyle:, jako jedyny opublikowany inicjator w dokumentach, jest to jedno jednoznacznie określone inicjator.

initWithNibName:bundle: jest dziedziczona z UIViewController i jest wyznaczonym inicjatorem dla tej klasy. Jako taki, zgodnie z wytycznymi Cocoa, UITableViewControllermusi zastąpić tę metodę (poprzez jej wdrożenie). Jednak nie oznacza to, że jest to inicjator o nazwie UITableViewController.

initWithCoder: to, jak wskazujesz, domyślny inicjator o nazwie NSCoding.

7

Wewnętrznie

  • UITableViewController na -initWithStyle: nazywa super na -init następnie ustawić _tableViewStyle ivar.
  • UIViewController's -init po prostu wywołuje -initWithNibName:bundle: z domyślnymi argumentami.
  • UITableViewController nie zastępuje przesłaniem -initWithNibName:bundle:.

Dlatego też, jeśli zastąpisz -initWithNibName:bundle:, wówczas również zmiana zostanie przyjęta przez -initWithStyle:. Oczywiście, aby grać bezpiecznie (ponieważ nie powinieneś polegać na szczegółach implementacji), zastąp oba.

(i nie ma potrzeby, aby zastąpić -initWithCoder: chyba że będzie un/archiwum instancje.)

+0

Przesłanianie -initWithNibName: bundle: samo w sobie powinno być bezpieczne, ponieważ tak naprawdę nie jest to szczegół implementacji, ale aspekt frameworka, w którym wyznaczone inicjatory są wywoływane aż do łańcucha dziedziczenia. A ten łańcuch dziedziczenia jest częścią interfejsu UITableViewController. – TBBle

0

Dodatek do słupków powyżej tego -initWithCoder odniesienia:

jeśli dodano dodany kontroler widoku do jego rodzica za pośrednictwem budowniczego interfejsu (na przykład: jeśli kontroler widoku jest podłączony do kontrolera paska kart w programie budującym interfejs), musisz przesłonić -initWithCoder.

(-initWithNibName zostanie wywołana tylko podczas tworzenia kontrolera widoku programowo.)

Powiązane problemy