Dlaczego nie mogę wywołać domyślnej super.init () na UIViewController w Swift?


84

Nie używam UIViewControllerz storyboardu i chcę mieć niestandardową initfunkcję, w której przekazuję NSManagedObjectIDjakiś obiekt. Chcę tylko zadzwonić, super.init()tak jak w przypadku Objective-C. Lubię to:

init(objectId: NSManagedObjectID) {
    super.init()
}

Ale pojawia się następujący błąd kompilatora:

Musi wywołać wyznaczony inicjator klasy UIViewController nadklasy

Czy mogę już tego po prostu nie robić?

Odpowiedzi:


119

Wyznaczony inicjator dla UIViewControllerto initWithNibName:bundle:. Zamiast tego powinieneś tak zadzwonić.

Zobacz http://www.bignerdranch.com/blog/real-iphone-crap-2-initwithnibnamebundle-is-the-designated-initializer-of-uiviewcontroller/

Jeśli nie masz końcówki, przekaż ją nildla nibName (pakiet też jest opcjonalny). Następnie można skonstruować własny widok w loadViewlub przez dodanie do subviews self.vieww viewDidLoad, tak samo jak kiedyś.


4
Więc obecnie nie mogę utworzyć niestandardowej metody init w podklasie UIViewController, która nie pochodzi z końcówki?
SirRupertIII

1
Ahh, dzięki !! Podaję „” jako nazwę stalówki.
SirRupertIII,

2
Och, po krótkich poszukiwaniach okazuje się, że initWithCoder:pochodzi z NSCodingprotokołu ... Nadal nie mogę dowiedzieć się, jaka jest jego rola w inicjowaniu instancji UIViewController, czy jest to „wyznaczony” inicjator UIViewController, czy też dowolna z jego klas nadrzędnych. ,
Nicolas Miari,

6
Dzięki! Do szybkiego kopiowania / wklejania właśnie nazywają to po ustawieniu swoich letwłaściwości, jeżeli występuje: super.init(nibName: nil, bundle: nil).
Ferran Maylinch

3
Init With coder jest używany, gdy musisz przywrócić stan. Gdy zapiszesz stan kontrolera widoku za pomocą funkcji przywracania stanu, koder zwróci wartości zapisane podczas zapisywania stanu. Stamtąd możesz odbudować kontroler widoku do jego ostatniego stanu początkowego od momentu zamknięcia aplikacji. Więc dla użytkownika to miejsce, w którym zakończyli
Esko918

44

Innym fajnym rozwiązaniem jest zadeklarowanie nowego inicjatora jako convenienceinicjatora w następujący sposób:

convenience init( objectId : NSManagedObjectID ) {
    self.init()

    // ... store or user your objectId
}

Jeśli w ogóle nie zadeklarujesz żadnych wyznaczonych inicjatorów w swojej podklasie, zostaną one odziedziczone automatycznie i możesz użyć ich self.init()w wygodnym inicjatorze.

W przypadku UIViewController domyślna metoda init zadzwonić init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!)z nilobu argumentów (Command na UIViewController daje te informacje).

TL; TR : Jeśli wolisz programistycznie pracować z UIViewControllers, oto kompletny przykład roboczy, który dodaje nowy inicjator z niestandardowym argumentem:

class MyCustomViewController: UIViewController {
    var myString: String = ""

    convenience init( myString: String ) {
        self.init()

        self.myString = myString
    }
}

Jest to bardziej eleganckie rozwiązanie i działa w każdym ogólnym przypadku
Ciprian

2
Próbowałem to zrobić w rozszerzeniu i rekurencyjnie się nazywał.
Danyal Aytekin

12
„Sztuczka” w tej odpowiedzi polega na tym, że myStringjest ustawiona na wartość, ""więc initnie jest wymagana. To rozwiązanie rozpada się, jeśli nie chcesz używać wartości początkowej, a w takim przypadku musisz użyćself.init(nibName: nil, bundle:nil)
Dan Rosenstark

2
@Yar lub uczynisz myStringnieruchomość opcjonalną
Klaas

1
@Klaas tak: moim problemem jest to, że używałem inicjatorów TYLKO w celu uniknięcia opcji i skompilowania mojego kodu.
Dan Rosenstark

18

Aby poprawić odpowiedź okulusa :

init() {
     super.init(nibName: nil, bundle: nil)
}

15

Aktualizacja: dodaj link

https://developer.apple.com/documentation/uikit/uiviewcontroller/1621359-init

Zgodnie z dokumentacją dla systemu iOS wyznaczonym inicjatorem dla UIViewController jest initWithNibName: bundle:.

Jeśli podklasa UIViewController jest podrzędna, musisz wywołać super implementację tej metody, nawet jeśli nie używasz NIB.

Możesz to zrobić w następujący sposób:

init(objectId : NSManagedObjectID) {

    super.init(nibName: (xib's name or nil'), bundle: nil)

   // other code...
}

lub

Zadeklaruj nowy inicjator jako wygodny inicjator:

 convenience init( objectId : NSManagedObjectID ) {

    self.init()

     // other code...

}


1
W celu atrybucji umieść link do oryginału, zamiast pozostawiać go jako zrzut ekranu.
Nathan Tuggy

Użyłem tego samego procesu, co powiedział @NcNc. U mnie to zadziałało. Oto link
Anil Gupta

@NathanTuggy Nie, nie powinien. Linki mają funkcję, która kiedyś wygasa lub zostanie przeniesiona. Kto chce zobaczyć błąd 404 zamiast informacji, których szuka?
mykolaj

1
@mykolaj: Informacje już są w tej odpowiedzi. (W przeciwnym razie zgłosiłbym do usunięcia jako odpowiedź zawierającą tylko łącze). Jednak atrybucja jest również ważna, aby każdy, kto to czyta, mógł dowiedzieć się, skąd pochodzi, i wymienić je. Zrzut ekranu nie działa w tym przypadku, ale link działa. Jeśli link gnije, to niefortunne, ale nie możesz mi powiedzieć, że to gorsza sytuacja niż brak jakiegokolwiek kredytu. Zarzuty, które SO musi dotyczyć tylko linków, dotyczą tylko linków . Nie do linków. Link, a także informacje to pożądane sformułowanie.
Nathan Tuggy

@NathanTuggy Właśnie dodałem link. Dziękuję za przypomnienie
NcNc
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.