Чому я не можу зателефонувати за замовчуванням super.init () на UIViewController у Swift?


84

Я не використовую a UIViewControllerз розкадрування, і я хочу мати власну initфункцію, де я передаю NSManagedObjectIDякийсь об’єкт. Я просто хочу зателефонувати, super.init()як у Objective-C. Подобається це:

init(objectId: NSManagedObjectID) {
    super.init()
}

Але я отримую таку помилку компілятора:

Потрібно викликати призначений ініціалізатор суперкласу UIViewController

Чи можу я просто більше цього не робити?

Відповіді:


119

Призначений ініціатор для UIViewControllerє initWithNibName:bundle:. Натомість вам слід зателефонувати.

див http://www.bignerdranch.com/blog/real-iphone-crap-2-initwithnibnamebundle-is-the-designated-initializer-of-uiviewcontroller/

Якщо у вас немає перо, передайте nilім’я nibName (комплект також не є обов’язковим). Тоді можна побудувати для користувача подання до loadViewабо шляхом додавання підвидів до self.viewв viewDidLoad, так само , як ви звикли.


4
Отже, в даний час мені неможливо створити власний метод init у підкласі UIViewController, який не з перового переходу?
SirRupertIII

1
Ааа, дякую !! Я передавав "" ім'я перо.
SirRupertIII

2
О, після невеликого копання, виявляється, це initWithCoder:походить з NSCodingпротоколу ... Я все ще не можу зрозуміти, яка його роль в ініціалізації екземпляра UIViewController, чи це "призначений" ініціалізатор UIViewController або будь-який з його суперкласів .. .
Ніколя Міар

6
Дякую! Для швидкого копіювання / вставки просто називаємо це після установки ваших letвластивостей, якщо такі є: super.init(nibName: nil, bundle: nil).
Ферран Мейлінч,

3
Init With кодер використовується, коли вам потрібно зробити відновлення стану. Коли ви зберігаєте стан контролера перегляду за допомогою функцій відновлення стану, кодер повертає значення, збережені вами при збереженні стану. Звідти ви можете відновити контролер перегляду до останнього початкового стану з моменту закриття програми. Тож користувачеві, звідки вони зупинились
Esko918

44

Іншим приємним рішенням є оголошення нового ініціалізатора як convenienceініціалізатора наступним чином:

convenience init( objectId : NSManagedObjectID ) {
    self.init()

    // ... store or user your objectId
}

Якщо ви взагалі не заявляєте призначених ініціалізаторів у своєму підкласі, вони успадковуються автоматично, і ви можете використовувати їх self.init()у своєму зручному ініціалізаторі.

У разі UIViewController метод ініціалізації за замовчуванням буде викликати init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!)з nilобох аргументів (Command-Click на UIViewController дасть вам цю інформацію).

TL; TR : Якщо ви віддаєте перевагу програмній роботі з UIViewControllers, ось повний робочий приклад, який додає новий ініціалізатор із користувацьким аргументом:

class MyCustomViewController: UIViewController {
    var myString: String = ""

    convenience init( myString: String ) {
        self.init()

        self.myString = myString
    }
}

Це більш елегантне рішення, яке працює в будь-якому загальному випадку
Ciprian

2
Я спробував зробити це в розширенні, і воно рекурсивно назвало себе.
Даніал Айтекін

12
"Фокус" у цій відповіді полягає в тому, що myStringвстановлено значення, ""тому initне потрібно. Це рішення розпадається, якщо ви не хочете використовувати початкове значення, і в такому випадку вам потрібно використовуватиself.init(nibName: nil, bundle:nil)
Ден Розенстарк

2
@Yar або ви робите myStringвласність необов’язковою
Клаас,

1
@Klaas так: моя проблема полягає в тому, що я використовував ІНІТАЛІЗАТОРИ ТІЛЬКИ для того, щоб уникнути додаткових можливостей і отримати свій код для компіляції.
Dan Rosenstark,


15

Оновлення: додайте посилання

https://developer.apple.com/documentation/uikit/uiviewcontroller/1621359-init

Згідно з документацією для iOS, призначеним ініціатором для UIViewController є initWithNibName: bundle:.

Якщо ви підклас UIViewController, ви повинні викликати супер реалізацію цього методу, навіть якщо ви не використовуєте NIB.

Ви можете зробити це наступним чином:

init(objectId : NSManagedObjectID) {

    super.init(nibName: (xib's name or nil'), bundle: nil)

   // other code...
}

або

Оголосіть новий ініціалізатор зручним ініціалізатором:

 convenience init( objectId : NSManagedObjectID ) {

    self.init()

     // other code...

}


1
Вам слід посилатися на оригінал для атрибуції, а не залишати його як заставку.
Натан Таггі,

Я використовував той самий процес, що і @NcNc. У мене це спрацювало. Ось посилання
Аніл Гупта

@NathanTuggy Ні, він не повинен. Посилання має функцію, яка колись закінчується чи переміщується. Хто хоче побачити помилку 404 замість інформації, яку він / вона шукає?
Миколай 15.03.18

1
@mykolaj: Інформація вже є тут, у цій відповіді. (В іншому випадку я б позначав для видалення як відповідь лише на посилання.) Але атрибуція також важлива, щоб кожен, хто читає це, міг дізнатися, звідки він взявся, і зарахувати їх. Знімок екрану для цього не працює, але посилання працює. Якщо посилання загниває, це прикро, але ви не можете сказати мені, що це гірша ситуація, ніж взагалі відсутність будь-якого кредиту. Заперечення SO повинні посилання тільки відповіді на ссилка- тільки відповіді. Не до посилань. Посилання, а також інформація - це бажане формулювання.
Натан Таггі,

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