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

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

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

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

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

1 ответов


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

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

вместо этого вы можете удалить optionality / failability с небольшой песней и танцем:

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's wrong
    }
    convenience override init() {
        self.init(nibName: "MainView", bundle: nil)
    }

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

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

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


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

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