Подтвердить что ты не робот

Правильный способ переопределить инициализатор в Swift 1.1

Это использовалось для работы в Xcode 6.1 beta:

class MainViewController: NSViewController {
  convenience override init() {
    self.init(nibName: "MainView", bundle: nil)
  }
}

После переключения на 6.1 GM2 он не компилируется. Похоже, проблема связана с "отказоустойчивыми инициализаторами", представленной в Swift 1.1. Я пробовал convenience override init?(), convenience init?() и override init?(), не работал.

Итак, каков правильный способ переопределить этот тип инициализаторов на сегодняшний день?

4b9b3361

Ответ 1

Вы пытаетесь реализовать init() - инициализатор без отказов - делегируя init?(nibName:bundle:), что является неудачным инициализатором. Это не сработает: если вызов super.init завершился неудачно, вы останетесь с неинициализированным экземпляром, который Swift не разрешит.

Или, говоря иначе, результат использования инициализатора с ошибкой является необязательным, и вы не можете использовать опцию вместо необязательного значения. А в случае инициализации и наследования классов вы не можете заменить необязательный self для необязательного - вы можете делегировать настройку состояния self на другой инициализатор.

Вместо этого вы можете удалить опциональность/отказоустойчивость с помощью небольшой песни и танца:

class MainViewController: NSViewController {
    override init!(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        // check state here and provide app-specific diagnostic if it wrong
    }
    convenience override init() {
        self.init(nibName: "MainView", bundle: nil)
    }

    // need this, too, or the compiler will complain that it missing
    required init?(coder: NSCoder) {
        fatalError("not implemented") // ...or an actual implementation
    }
}

An init! инициализатор создает неявно развернутый необязательный (IUO) - так же, как тип IUO может использоваться для соединения между кодом, который работает с необязательными и необязательными значениями, инициализатор init! может связывать между failable и non -failable инициализаторы. Вы не можете делегировать из инициализатора, не являющегося отказоустойчивым, в неудачный инициализатор, но вы можете делегировать из инициализатора без отказа в инициализатор init! и из инициализатора init! в неудачный инициализатор.

Здесь инициализатор NSViewController, который вы хотите использовать, полностью отказоустойчив, поэтому вы переопределяете его с помощью инициализатора init!. Затем вы можете объявить non-failable convenience init, который делегирует ваш новый инициализатор init!.


Мы часто стараемся избегать IUO и расширения init! инициализаторы, потому что мы обычно хотим либо явно разрешить (и потребовать обработки) отказ, либо явно запретить его. Тем не менее, один из самых сильных общих случаев использования для IUO и их родственников - это превратить условия, гарантированные только за пределами вашего исходного кода, в утверждения, что ваш код может считаться безошибочным. IBOutlet - отличный пример этого - в вашем nib/раскадровке вы гарантируете состояние своих переменных IBOutlet, но компилятор не знает об этом - так же, как и все, что связано с ресурсами пакета.

Этот небольшой танцевальный танец ставит бремя неудачи в определенном, легко отлаживаемом месте в вашем коде - если сбой от init() до super.init(nibName:bundle:) не удастся, ваше приложение выйдет из строя. Но вы можете ожидать, что вызов будет терпеть неудачу только в очень специфических (и в основном в процессе разработки) условиях.