Swift: niestandardowe inicjatory ViewController

87

Jak dodać niestandardowe inicjatory do UIViewControllerpodklas w Swift?

Utworzyłem podklasę, UIViewControllerktóra wygląda mniej więcej tak:

class MyViewController : UIViewController
{
    init(leftVC:UIViewController, rightVC:UIViewController, gap:Int)
    {
        self.leftVC = leftVC;
        self.rightVC = rightVC;
        self.gap = gap;

        super.init();

        setupScrollView();
        setupViewControllers();
    }
}

Po uruchomieniu otrzymuję fatalny błąd:

błąd krytyczny: użycie niezaimplementowanego inicjatora „init (nibName: bundle :)” dla klasy „MyApp.MyViewController”

Czytałem gdzie indziej, że dodając niestandardowy inicjalizator, należy go również przesłonić, init(coder aDecoder:NSCoder)więc zastąpmy to initi zobaczmy, co się stanie:

override init(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder);
}

Jeśli dodam to, Xcode narzeka self.leftVC is not initialized at super.init call. Więc myślę, że to też nie może być rozwiązaniem. Zastanawiam się więc, jak mogę poprawnie dodać niestandardowe inicjatory do ViewControllerpodklasy w Swift (ponieważ w Objective-C wydaje się, że nie stanowi to problemu)?

BadmintonCat
źródło
Jak próbujesz utworzyć wystąpienie MyViewController?
Mike Pollard
Dlaczego nie instancję wszystko w viewDidLoad (), nie można zainicjować je tak, jak chcesz
tudoricc
@MikePollard with dualViewCtrl = DualViewCtrl (leftVC: l, rightVC: r, gap: 50) ... Dowiedziałem się już, że muszę użyć inicjatora initWithNib.
BadmintonCat
3
@tudoricc Ponieważ często potrzebujesz właściwości instancji, które są bezpiecznie inicjowane w inicjatorze z podanymi parametrami. Nie możesz tego zrobić w viewDidLoad, ponieważ wtedy nie ma gwarancji, że właściwości będą dostępne w razie potrzeby.
BadmintonCat
Przepraszam, tylko że w mojej głowie widzę viewDidLoad () jako inicjalizator. dzięki za wyjaśnienie
tudoricc

Odpowiedzi:

124

Rozwiązałem to! Należy wywołać wyznaczony inicjator, którym w tym przypadku jest init z nibName, oczywiście ...

init(leftVC:UIViewController, rightVC:UIViewController, gap:Int)
{
    self.leftVC = leftVC
    self.rightVC = rightVC
    self.gap = gap

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

    setupScrollView()
    setupViewControllers()
}
BadmintonCat
źródło
31
Pozbądź się tych brzydkich
średników
8
Lubię średniki. Sprawiają, że kod jest mniej niejednoznaczny, zwłaszcza w przypadku śmiesznie gadatliwych nazw i podpisów API Cocoa / Cocoa-Touch. Zła decyzja projektantów Swift, aby usunąć je IMHO.
BadmintonCat
25
IMHO, jeśli wpiszesz znak i nie wpłynie to na skompilowany plik binarny, nie powinieneś go wpisywać :)
Sam Soffes
32
@SamSoffes, więc w ogóle nie używasz (dodatkowych) białych znaków? I zaciemniasz wszystkie symbole, aby były pojedynczymi znakami?
Victor Jalencas
8
Ta dyskusja przypomina mi tabulatory vs spacje w Dolinie Krzemowej
Aaron
13

Aby uzyskać bardziej ogólny kontroler UIViewController, możesz użyć tego od wersji Swift 2.0

init() {
    super.init(nibName: nil, bundle: nil)
}
Tr0yJ
źródło
11

Nie jestem pewien, czy udało Ci się w pełni rozwiązać ten problem ... ale w zależności od tego, jak chcesz wyglądać interfejs Twojej klasy i czy faktycznie potrzebujesz funkcji kodera, możesz również użyć poniższego:

convenience required init(coder aDecoder: NSCoder)
{
    //set some defaults for leftVC, rightVC, and gap
    self.init(leftVC, rightVC, gap)
}

Ponieważ init:leftVC:rightVC:gapjest wyznaczonym inicjatorem, możesz spełnić wymóg implementacjiinit:coder , czyniąc go wygodnym inicjatorem, który wywołuje wyznaczony inicjator.

To mogłoby być lepsze niż

override init(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder);
}

ponieważ jeśli chcesz zainicjować niektóre właściwości, musisz je przepisać.

wlingke
źródło
8

Szybki 5

Jeśli chcesz napisać niestandardowy inicjator, do UIViewControllerktórego jest inicjowany zstoryBoard.instantiateViewController(withIdentifier: "ViewControllerIdentifier")

Możesz napisać niestandardowy inicjator tylko dla Optionalwłaściwości.

class MyFooClass: UIViewController {
    var foo: Foo?

    init(with foo: Foo) {
        self.foo = foo
        super.init(nibName: nil, bundle: nil)
    }

    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.foo = nil
    }
}
emrcftci
źródło