Що саме є init coder aDecoder?


122

Я навчаюсь розробці iOS за допомогою онлайн-курсу, і кожного разу, коли я створюю власні подання (власна комірка подання таблиці, комірка подання колекції тощо), інструктор завжди реалізує цей ініціалізатор:

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

Чому саме я завжди повинен це називати? Що це робить? Чи можу я помістити властивості всередині init?


5
Відповідь на це питання допоможе stackoverflow.com/questions/24036393 / ... Спасибі
Seungyoun Yi

2
Якщо ви підкласируєте об'єкт, який реалізує, NSCodingто вам потрібно реалізувати цей ініціалізатор, оскільки це потрібно для класів, які реалізують NSCoding. Вам потрібно принаймні викликати метод init надкласового рівня. Якщо NSCoderмістять закодовані властивості для вашого класу, тоді ви можете скористатися цим методом, щоб відновити їх
Paulw11

1
Також рекомендую ознайомитись з розділом про ініціалізацію об'єктів в офіційній книзі Swift від Apple.
Nicolas Miari

Відповіді:


121

Я розпочну цю відповідь з протилежного напрямку: що робити, якщо ви хочете зберегти стан свого перегляду на диску? Це відомо як серіалізація . Реверс - десеріалізація - відновлення стану об’єкта з диска.

NSCodingПротокол визначає два методи для сериализации і десеріалізациі об'єктів:

encodeWithCoder(_ aCoder: NSCoder) {
    // Serialize your object here
}

init(coder aDecoder: NSCoder) {
    // Deserialize your object here
}

То чому це потрібно у вашому користувальницькому класі? Відповідь - це Interface Builder. Коли ви перетягуєте об’єкт на дошку та налаштовуєте її, Interface Builder серіалізує стан цього об’єкта на диску, а потім десеріалізує його, коли на екрані з’явиться сцена. Вам потрібно сказати Interface Builder, як це зробити. Принаймні, якщо ви не додаєте до свого підкласу жодних нових властивостей, ви можете просто попросити суперклас зробити упаковку та розпакування для вас, отже, super.init(coder: aDecoder)дзвінок. Якщо ваш підклас складніший, вам потрібно додати свій власний код серіалізації та десеріалізації для підкласу.

Це на відміну від підходу Visual Studio, який полягає в тому, щоб записати код у прихований файл, щоб зробити об'єкт під час виконання.


Чому б не поставити все все прокинутесь від «NFB» і не забути використовувати init(coder aCoder : NSCoder)?
Мед

@Honey - одним словом, "іноді ти цього не можеш зробити". Зазвичай ви можете, але не завжди.
Fattie

@Fattie - це деталі того, щоб не робити це занадто складно або непотрібно знати? Якщо ви не проти пояснити?
Мед

9
@Honey, якщо ви хочете налаштувати свій об'єкт у Interface Builder, тоді awakeFromNibвін не працюватиме. awakeFromNibвикликається під час виконання . Все, що ви робите в Interface Builder - це під час проектування . Для того, щоб нести то , що ви зробили в режимі розробки на час виконання є encodeWithCoder(економія) і init(coder:)(погрузка)
кодекс Different

3
@Honey, якщо ви не використовуєте Interface Builder для налаштування власного класу (тобто це робите програмно з кодом), тоді ви можете це зробити в awakeFromNibабоinitWIthFrame
Code Different

28

Вимога реалізації цього ініціалізатора є наслідком двох речей:

  1. Принцип заміщення Ліски . Якщо S - підклас T (наприклад MyViewController, підклас ViewController), то S об'єкти (екземпляри MyViewController) повинні бути здатні бути замінені там, де ViewControllerочікуються T об'єкти (екземпляри ).

  2. Ініціалізатори не успадковуються в Swift, якщо будь-які ініціалізатори явно визначені в підкласі. Якщо явно надано один ініціалізатор, то всі інші повинні бути явно надані (які потім можуть просто викликати super.init(...)). Дивіться це питання для обґрунтування. Це на Java, але все ще застосовується.

У пункті 1 все, що ViewControllerможе зробити оригінал , MyViewControllerпідклас повинен бути в змозі зробити. Одне таке - це можливість бути ініціалізованою від заданої NSCoder. До пункту 2 ваш MyViewControllerпідклас автоматично не успадковує цю здатність. Таким чином, ви повинні вручну поставити ініціалізатор, який відповідає цій вимозі. У цьому випадку вам просто потрібно делегувати до суперкласу, щоб він міг робити те, що зазвичай робив.


1
Має сенс, що конструктори не успадковуються: Якщо ви ініціалізуєте екземпляр похідного класу за допомогою (успадкованого) ініціалізатора базового класу, не успадковані властивості, які були щойно визначені ("додані") похідним класом, ніколи не будуть ініціалізувати.
Nicolas Miari

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