2014-10-08 13 views
13

To używane do pracy w Xcode 6.1 beta:Prawidłowy sposób zastąpić inicjatora w Swift 1.1

class MainViewController: NSViewController { 
    convenience override init() { 
    self.init(nibName: "MainView", bundle: nil) 
    } 
} 

Po przełączeniu do 6,1 GM2, nie skompilować. Wygląda na to, że problem jest związany z "failable initializers" wprowadzonym w Swift 1.1. Próbowałem convenience override init?(), convenience init?() i override init?(), i nie działałem.

Jaki jest właściwy sposób na zastąpienie tego rodzaju inicjatorów od dzisiaj?

Odpowiedz

20

Próbujesz wdrożyć init() - niezawodny inicjator - poprzez delegowanie do init?(nibName:bundle:), który jest inicjatorem awaryjnym. To nie działa: jeśli wywołanie super.init nie powiedzie się, pozostanie niezainicjowana instancja, na którą Swift nie zezwoli.

Albo, ujmując to inaczej, wynik użycia inicjalizatora awaryjnego jest opcjonalny i nie można użyć opcjonalnego zamiast wartości opcjonalnej. W przypadku inicjowania klasy i dziedziczenia nie można zastąpić nie-opcjonalnego modelu self jako opcjonalnego - można przekazać tylko konfigurację stanu self do innego inicjalizatora.

Zamiast tego można usunąć opcjonalności/failability z trochę pieśni i tańca:

class MainViewController: NSViewController { 
    override init!(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 
     super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 
     // check state here and provide app-specific diagnostic if it's wrong 
    } 
    convenience override init() { 
     self.init(nibName: "MainView", bundle: nil) 
    } 

    // need this, too, or the compiler will complain that it's missing 
    required init?(coder: NSCoder) { 
     fatalError("not implemented") // ...or an actual implementation 
    } 
} 

init! inicjator wywołuje niejawnie nieopakowanych opcjonalnego (IUO) - podobnie jak typ IUO może być użyty do pokonania między kodem który działa z wartościami opcjonalnymi i nie-opcjonalnymi, inicjator init! może łączyć między inicjatorami awaryjnymi i niezniszczalnymi. Nie można przekazać inicjalizatora, który nie może zostać uszkodzony, do awaryjnego inicjalizatora, ale można przekazać inicjator niezawierający awarii inicjatorowi init! i inicjatorowi init! do inicjalizatora awaryjnego.

Tutaj inicjator NSViewController, którego chcesz użyć, jest w pełni uszkodzony, więc zastąp go inicjalizatorem init!. Następnie można zadeklarować niezawodny kod convenience init, który deleguje do nowego inicjatora init!.


Często unikają IUOs, a co za tym idzie init! inicjatorów, ponieważ na ogół chcą jawnie zezwolić na (i wymagają obsługi) Uszkodzenie lub wyraźnie nie dopuścić do tego. Jednak jednym z najsilniejszych ogólnych przypadków użycia IUO i ich krewnych jest przekształcenie warunków, które są gwarantowane tylko poza twoim kodem źródłowym, w twierdzenia, które twój kod może traktować jako nieomylny. IBOutlet s są tego świetnym przykładem - w swoim stalówce/scenorysie gwarantujesz stan zmiennych IBOutlet, ale kompilator o tym nie wie - podobnie jak wszystko, co należy zrobić z zasobami pakietu.

Ten mały taniec delegacji stawia ciężar porażki w określonym, łatwym do debugowania miejscu w kodzie - jeśli połączenie od init() do super.init(nibName:bundle:) nie powiedzie się, twoja aplikacja zawiesi się. Ale można oczekiwać, że wezwanie do porażki nastąpi tylko w bardzo specyficznych (i głównie w trakcie rozwoju) warunkach.

+11

szaleństwo. co powiesz na zwięzłość, proszę jabłko. –

+2

Daje to błąd w Swift 1.2: "Inicjator nie zastępuje wyznaczonego inicjalizatora z jego nadklasy" ... to znaczy nadpisanie na 2. init musi zostać usunięte. Nawet po tym, po kompilacji trzeciego inicjalizatora zgłasza swój błąd krytyczny. Jak to musi być wdrożone? – BadmintonCat

+0

To zbyt skomplikowane. –