Почему я не могу вызвать super.init () по умолчанию для UIViewController в Swift?

85

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

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

Но я получаю следующую ошибку компилятора:

Должен вызывать назначенный инициализатор суперкласса UIViewController

Могу я просто больше не делать этого?

Сэр Руперт III
источник

Ответы:

121

Назначенный инициализатор для UIViewControllerэто initWithNibName:bundle:. Вместо этого вы должны это называть.

См. Http://www.bignerdranch.com/blog/real-iphone-crap-2-initwithnibnamebundle-is-the-designated-initializer-of-uiviewcontroller/

Если у вас нет пера, nilзамените nibName (комплект также необязателен). Затем вы можете создать собственное представление в loadViewили путем добавления вложенных представлений в self.viewin viewDidLoad, как вы это делали раньше.

оккулус
источник
4
Значит, в настоящее время я не могу создать собственный метод инициализации в подклассе UIViewController, который не из пера?
SirRupertIII
1
Ах, спасибо !! Я передавал "" вместо имени пера.
SirRupertIII
2
О, после небольшого поиска выясняется, что это initWithCoder:исходит из NSCodingпротокола ... Я до сих пор не могу понять, какова его роль в инициализации экземпляра UIViewController, является ли он "назначенным" инициализатором UIViewController или любого из его суперклассов ... .
Николя Миари
6
Благодаря! Для быстрого копирования / вставки просто называем это после установки ваших letсвойств, если таковые имеются: super.init(nibName: nil, bundle: nil).
Ферран Мэйлинч
3
Init With coder используется, когда вам нужно восстановить состояние. Когда вы сохраняете состояние контроллера просмотра с помощью функции восстановления состояния, кодер вернет значения, которые вы сохранили при сохранении состояния. Оттуда вы можете восстановить контроллер представления до его последнего начального состояния, когда вы закрыли приложение. Итак, для пользователя это то, с чего они остановились
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 да: моя проблема в том, что я использовал инициализаторы ТОЛЬКО, чтобы избежать опций и заставить свой код скомпилировать.
Дэн Розенстарк
19

Чтобы улучшить ответ оккулуса :

init() {
     super.init(nibName: nil, bundle: nil)
}
Вячеслав
источник
16

Обновление: добавьте ссылку

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...

}

NcNc
источник
1
Вы должны ссылаться на оригинал для указания авторства, а не оставлять его как снимок экрана.
Nathan Tuggy
Я использовал тот же процесс, что и @NcNc. У меня это сработало. Вот ссылка
Анил Гупта
@NathanTuggy Нет, не должен. У ссылок есть возможность истечь или когда-нибудь переместиться. Кто хочет видеть ошибку 404 вместо информации, которую ищет?
mykolaj
1
@mykolaj: Информация уже здесь, в этом ответе. (В противном случае я бы пометил удаление как ответ, содержащий только ссылку.) Но также важна атрибуция, так что любой, кто читает это, может узнать, откуда оно взято, и указать их. Снимок экрана не работает, а ссылка работает. Если ссылка гниет, что ж, это прискорбно, но вы не можете сказать мне, что это хуже, чем отсутствие каких-либо кредитов. Возражения SO должны ссылка только ответы на ссылка- только ответы. Не к ссылкам. Ссылка, а также информация - это желаемая формулировка.
Nathan Tuggy
@NathanTuggy Я только что добавил ссылку. Спасибо за напоминание
NcNc