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ć

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



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.


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)
}

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.


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ął


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.


możesz również zadeklarować swoją właściwość jako opcjonalną za pośrednictwem ?.
Julian B.
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.