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ć?

SirRupertIII
źródło

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ś.

occulus
źródło
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
    }
}
Klaas
źródło
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)
}
Wiaczesław
źródło
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...

}

NcNc
źródło
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