Фатальна помилка: використання невтіленого ініціалізатора 'init (coder :)' для класу


156

Я вирішив продовжити свій залишився проект зі Свіфт. Коли я додаю користувальницький клас (підклас UIViewcontroller) до свого контролера подання розкадрівки та завантажую проект, додаток раптово виходить із ладу із наступною помилкою:

фатальна помилка: використання невтіленого ініціалізатора 'init (coder :)' для класу

Це код:

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.
    }
    */
}

Будь ласка, підкажіть щось

Відповіді:


207

Проблема

Це викликано відсутністю ініціалізатора init?(coder aDecoder: NSCoder)в цілі UIViewController. Цей метод необхідний, тому що екземпляр a UIViewControllerз його UIStoryboardвикликає.

Щоб побачити, як ми ініціалізуємо UIViewControllerа UIStoryboard, перегляньте тут

Чому це не є проблемою з Objective-C?

Тому що Objective-C автоматично успадковує всі необхідні UIViewControllerініціалізатори.

Чому Swift автоматично не успадковує ініціалізатори?

За замовчуванням Swift не успадковує ініціалізатори через безпеку. Але він успадкує всі ініціалізатори від надкласу, якщо всі властивості мають значення (або необов'язкове), а підклас не визначив жодних призначених ініціалізаторів.


Рішення

1. Перший метод

Ручне реалізація init?(coder aDecoder: NSCoder)на ціліUIViewController

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

2. Другий метод

Якщо вилучите init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)ціль, UIViewControllerви успадкуєте всі необхідні ініціалізатори від суперкласу, як Дейв Вуд вказав на свою відповідь нижче



4
Дякую за це Швидке дотримання ... Коли ви створюєте файл TableViewController, Xcode вже включає в себе init(style: UITableViewStyle) { super.init(style: style) // Custom initialization } Чому ми можемо мати дві функції init? І будь-яка ідея, чому Apple не включає 2-го init за замовчуванням?
Тревор МакКендрік

Це не має нічого спільного з iOS 7 або iOS 8. Це пов'язано з тим, як Swift успадковує інтитіалізатори!
Султан

public init (перегляд: UIViewController, кадр: CGRect) {self.viewController = переглянути self.imageName = "" self.actionName = "" super.init (frame: frame)}
scrainie

Перший метод спрацював! Моя динамічна таблиця нарешті заповнена динамічними осередками !!! Все тому, що рядок fatalError( "init(coder:) has not been implemented")зупинив мій додаток.
Хосе Мануель Абарка Родрігес

25

Ще один варіант, окрім @ 3r1d's, - це замість того, щоб видалити наступний метод init зі свого класу:

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

У тому числі цей метод init не дозволяє успадковувати підклас init(coder aDecoder: NSCoder!)від свого суперкласу. Якщо не включити його, ваш клас успадкує обоє.

Примітка: Дивіться сесію 403 WWDC "Проміжний стрім" близько 33:50 для більш детальної інформації.


Дякуємо, що вказали на пояснення на сесії 403. Але якщо дочірній клас має лише ініціалізатори зручності, то він успадкує ініціалізатори суперкласів?
jamiltz

1
Так. Ви забороняєте успадковувати методи суперкласу init, лише якщо ви надаєте власні призначені методи init (ті, що викликають суперініти). Тоді вам слід вказати, який із суперінітів підтримувати, додавши їх у свій клас та просто зателефонувавши до суперверсії (як у відповіді @ 3r1d)
Дейв Вуд

Наявність лише зручності init () без (призначеного) init () у вашому дочірньому класі призведе до помилки компіляції. Це тому, що функція зручності init () повинна викликати self.init () усередині визначення функції.
Оммі

@narumolPug Це неправильно. Вам не потрібно включати призначені initметоди. Ваш дитячий клас успадкує їх від суперкласу. Ви все ще можете зателефонувати, self.init()яка виконає суперверсію.
Дейв Вуд

Точний момент відео можна дізнатися тут youtu.be/W1s9ZjDkSN0?t=2030
Мед

10

Для людей, які мають таку саму проблему зі швидким UICollectionViewCells, додайте код, який @ 3r1d запропонував, щоб ваш власний UICollectionViewCellклас, а не контролер перегляду:

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

про який UICollectionViewCell ви посилаєтесь? Ініт з кодером - це спосіб запустити viewController
E-Riddie

Не в цьому прикладі, але у випадку, якщо хтось має проблеми з цим (я це зробив) ... якщо ви намагаєтесь використовувати UICollectionViewController, у вашому користувальницькому файлі .swift файл потрібно поставити init з кодером.
Нік Яп

2
Вам потрібно додати цей код кожен раз при використанні цього способу створення екземпляра stackoverflow.com/questions/24035984 / ...
E-Riddie

3

Для тих, хто потребує код у Swift:

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

[Редагувати] Це стосувалося старішої версії Swift. Можливо, більше не працює.


3

У мене була ця проблема в програмній комірці collectionView, і, хоча оператор запитує про vc, я все-таки приземлився на це питання під час пошуку відповіді. Для мене питання було в мене

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

реалізовано, тож відповідь не спрацювала. Чого я не мав у комірці, був ініціалізатор:

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

Як тільки я додав це, помилка зникла


1

Замість того, щоб додавати деякі методи для того, щоб внутрішній механізм спрацював нормально, я б пішов з визначення моїх атрибутів як @lazy та ініціалізував їх прямо у межах класу.


Ви також можете оголосити свою власність як необов’язковий через ?.
Джуліан Б.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.