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.