Почему я должен продолжать объявлять тот же обязательный, но не реализованный инициализатор для init(кодер aDecoder) для моего программного подкласса UIViewController?

Возможно, это только я, но я нахожу некоторые аспекты стремительными... глупыми, если не сказать больше.

Я не использую Interface Builder большую часть времени, потому что мне нравится использовать PureLayout, Так что я надеялся сделать UIViewController подкласс, скажем PureViewController, который пригодился init без параметров:

class PureViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
    }

}

Но это не хорошо, потому что XCode говорит мне, что я должен также реализовать init(coder aDecoder: NSCoder), Ладно, все в порядке! Вот почему я сделал этот класс - так что мне не нужно делать это снова для подклассов.

class PureViewController : UIViewController {

    init() {
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

Хорошо, теперь вот что я не понимаю.

Я определяю подкласс, SomePureViewController : PureViewController с инициализатором init(viewModel:ICrackersViewModel)...

class SomePureViewController : PureViewController {

    init(viewModel:ICrackersViewModel) {
        super.init()
    }

}

Но это все еще хочет, чтобы я определил тот же самый глупый инициализатор, пока не придет королевство!

class SomePureViewController : PureViewController {

    init(viewModel:ICrackersViewModel) {
        super.init()
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

Теперь я понимаю идею - нет init(decoder) в моем подклассе, даже если он определен в своем родительском классе.

Может быть, я всегда имел дело с этим вопросом UIViewController и никогда не замечал этого раньше.

Мои вопросы следующие:

  1. Есть ли что-то, что я делаю неправильно, чтобы вызвать такое поведение?
  2. Есть ли какой-нибудь выход за пределы наследства, чтобы я мог избежать повторения?
  3. Есть ли в планах какие-либо планы по изменению этого?

3 ответа

Решение

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

Давайте предположим, базовый класс

class Base {
    let value: Int

    required init(value: Int) {
        self.value = value
    }
}

и функция

func instantiateWith5(cls: Base.Type) -> Base {
    return cls.init(value: 5)
}

тогда мы можем сделать

let object = instantiateWith5(Base.self)

Теперь, если кто-то определяет производный класс

class Derived: Base {
    let otherValue: Int

    init() {
        otherValue = 1
        super.init(value: 1)
    }

    required init(value: Int) {
        fatalError("init(value:) has not been implemented")
    }
}

Мы по крайней мере можем позвонить

let object2 = instantiateWith5(Derived.self)

нарушая LSP, но это проблема вашего кода, а не языка.

Swift должен гарантировать, что инициализаторы оставят ваши объекты в инициализированном состоянии, даже если они являются производными от базового объекта, поэтому я думаю, что изменение будет плохим. Если вы хотите определить UIViewController, который не десериализуем и, следовательно, нарушает LSP, это ваше решение - но не ждите, что язык поддержит вас в этом.

Я думаю, что это быстрый вопрос, и нет способа, как избежать этого. Мы все ненавидим этот инициализатор пустой - фатальной ошибки.

Поскольку инициализатор отмечен required ключевое слово, все подклассы должны реализовывать этот инициализатор, и они также должны указывать required на их реализацию, так что их подклассы также необходимы для его реализации.

Требуемые инициализаторы

Напишите требуемый модификатор перед определением инициализатора класса, чтобы указать, что каждый подкласс класса должен реализовывать этот инициализатор

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

Это было частью языка Swift с 1.0 и вряд ли изменится.

Проблема на самом деле связана с использованием required ключевое слово в определении класса UIViewController. Теоретически это можно изменить, но опять же я думаю, что это маловероятно.

Другие вопросы по тегам