Błąd krytyczny: użycie niezaimplementowanego inicjatora „init (koder :)” dla klasy

156

Postanowiłem kontynuować mój pozostały projekt w Swift. Kiedy dodam niestandardową klasę (podklasę UIViewcontroller) do mojego kontrolera widoku scenorysu i załaduję projekt, aplikacja nagle ulega awarii z następującym błędem:

błąd krytyczny: użycie niezaimplementowanego inicjatora „init (koder :)” dla klasy

To jest kod:

import UIKit

class TestViewController: UIViewController {

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        // Custom initialization
    }

    override func viewDidLoad() {
        super.viewDidLoad()
              // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    /*
    // #pragma mark - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
}

Proszę coś zasugerować

Pratik Bhiyani
źródło

Odpowiedzi:

207

Kwestia

Jest to spowodowane brakiem inicjatora init?(coder aDecoder: NSCoder)w miejscu docelowym UIViewController. Ta metoda jest wymagana, ponieważ tworzenie wystąpienia a UIViewControllerz a UIStoryboardwywołuje ją.

Aby zobaczyć, jak inicjalizujemy a UIViewControllerz a UIStoryboard, spójrz tutaj

Dlaczego nie jest to problem z Objective-C?

Ponieważ Objective-C automatycznie dziedziczy wszystkie wymagane UIViewControllerinicjatory.

Dlaczego Swift nie dziedziczy automatycznie inicjatorów?

Swift domyślnie nie dziedziczy inicjatorów ze względu na bezpieczeństwo. Ale odziedziczy wszystkie inicjatory z nadklasy, jeśli wszystkie właściwości mają wartość (lub są opcjonalne), a podklasa nie zdefiniowała żadnych wyznaczonych inicjatorów.


Rozwiązanie

1. Pierwsza metoda

Ręczne wdrażanie init?(coder aDecoder: NSCoder)na celuUIViewController

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

2. Druga metoda

Usunięcie init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)celu UIViewControllerspowoduje odziedziczenie wszystkich wymaganych inicjatorów z superklasy, jak Dave Wood wskazał na swoją odpowiedź poniżej


E-Riddie
źródło
4
Dzięki za to. Szybkie uzupełnienie ... Kiedy tworzysz plik TableViewController, Xcode już zawiera. init(style: UITableViewStyle) { super.init(style: style) // Custom initialization } Dlaczego możemy mieć dwie funkcje init? I jakikolwiek pomysł, dlaczego Apple domyślnie nie zawiera drugiego inicjalizacji?
Trevor McKendrick
Nie ma to nic wspólnego z iOS 7 lub iOS 8. Jest to związane ze sposobem, w jaki Swift dziedziczy inicjatory!
Sulthan
public init (widok: UIViewController, ramka: CGRect) {self.viewController = view self.imageName = "" self.actionName = "" super.init (frame: frame)}
scrainie
Pierwsza metoda zadziałała! Mój dynamiczny stół wreszcie wypełniony dynamicznymi komórkami !!! Wszystko dlatego, że linia fatalError( "init(coder:) has not been implemented")zatrzymała moją aplikację.
Jose Manuel Abarca Rodríguez
25

Inną opcją oprócz @ 3r1d jest usunięcie następującej metody init z klasy:

init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    // Custom initialization
}

Włączenie tej metody init zapobiega dziedziczeniu przez podklasę klasy po init(coder aDecoder: NSCoder!)swojej superklasie. Nie uwzględniając go, twoja klasa odziedziczy oba.

Uwaga: aby uzyskać więcej informacji, zobacz sesję 403 WWDC 2014 „Intermediate Swift” około godziny 33:50.

Dave Wood
źródło
Dzięki za wskazanie wyjaśnień dotyczących sesji 403. Ale jeśli klasa podrzędna ma tylko inicjatory wygodne, odziedziczy inicjatory superklasy, prawda?
jamiltz
1
Tak. Zapobiegasz dziedziczeniu super-klasowych metod inicjowania tylko wtedy, gdy dostarczysz własne wyznaczone metody init (te, które wywołują superinity). Następnie musisz określić, które z super initów mają być obsługiwane, dodając je do swojej klasy i po prostu wywołując super wersję (jak w odpowiedzi @ 3r1d)
Dave Wood
Mając tylko wygodę init () bez (wyznaczonego) init () w klasie potomnej, spowoduje to błąd kompilacji. Dzieje się tak, ponieważ wygodna funkcja init () musi wywoływać self.init () wewnątrz definicji funkcji.
Ohmy,
@narumolPug To nieprawidłowe. Nie musisz uwzględniać wyznaczonych initmetod. Twoja klasa podrzędna odziedziczy je po superklasie. Nadal możesz zadzwonić, self.init()co spowoduje wykonanie super wersji.
Dave Wood
Dokładny moment filmu można znaleźć tutaj youtu.be/W1s9ZjDkSN0?t=2030
Honey
10

Dla osób, które mają ten sam problem ze swift UICollectionViewCells, dodaj kod, który @ 3r1d zasugerował do twojej UICollectionViewCellklasy niestandardowej, a nie do kontrolera widoku:

init(coder aDecoder: NSCoder!)
{
    super.init(coder: aDecoder)
}
Nick Yap
źródło
do którego UICollectionViewCell masz na myśli? Init with coder to sposób na
zainicjowanie viewController
Nie w tym przykładzie, ale na wypadek, gdyby ktoś miał z tym problem (ja to zrobiłem) ... jeśli spróbujesz użyć UICollectionViewController, w swoim niestandardowym pliku .swift komórki musisz umieścić init z koderem.
Nick Yap
2
Musisz dodać ten kod za każdym razem, gdy używasz tego sposobu tworzenia instancji stackoverflow.com/questions/24035984/ ...
E-Riddie.
3

Dla tych, którzy potrzebują kodu w Swift:

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

[Edytuj] To było dla starszej wersji Swift. Prawdopodobnie już nie działa.

MXV
źródło
3

Miałem ten problem w komórce programmatic collectionView i mimo że operator pyta o vc, nadal wylądowałem na tym pytaniu podczas wyszukiwania odpowiedzi. Dla mnie problem polegał na tym, że miałem

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

wdrożone, więc pierwsza odpowiedź nie zadziałała. To, czego nie miałem w komórce, to inicjator:

// my programmatic cell was missing this
override init(frame: CGRect) {
    super.init(frame: frame)
}

Po dodaniu błąd zniknął

Lance Samaria
źródło
1

Zamiast dodawać metody poprawiające działanie mechanizmu wewnętrznego, zdecydowałbym się zdefiniować moje atrybuty jako @lazy i zainicjować je bezpośrednio w zakresie klasy.

hasancan85
źródło
możesz również zadeklarować swoją właściwość jako opcjonalną za pośrednictwem ?.
Julian B.