В чем разница между требуемым инициализатором и назначенным инициализатором?

Я создавал свой собственный tableViewCell, а затем я получил сообщение об ошибке:

'обязательный' инициализатор 'init (coder:)' должен быть предоставлен подклассом 'UITableViewCell'

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

Apple Docs говорит:

требуются Инициализаторы:

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

назначенные инициализаторы

назначенные инициализаторы являются основными инициализаторами для класса. Ля назначенный инициализатор полностью инициализирует все свойства, введенные этот класс и вызывает соответствующий суперкласс инициализатор для продолжения процесс инициализации вверх по цепочке суперклассов.

являются ли следующие утверждения правильными:

  • обязательным инициализатором всегда является назначенный инициализатор
  • каждый назначенный инициализатор не обязательно требуется инициализатор
  • класс может иметь только один требуемый инициализатор, однако он может иметь несколько назначенных инициализаторов?

сказав это, я все еще не полностью понять их функциональные различия.

1 ответов


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

Требуются Initialisers

A требуются инициализации тестов дает гарантию того, что вы можете инициализировать тип, или любой из его подтипов, что для инициализации тестов. Если у вас есть инициализатор в протоколе, и вы что-то соответствуете этому протоколу, вы должны использовать required (если это класс), потому что этот протокол гарантирует, что инициализатор присутствует в этом классе и любом из его подклассов. Когда вы используете required на инициализаторе класса, который сигнализирует, что все его подклассы также могут быть инициализированы с помощью этого метода. Это означает, что вам также нужно добавить этот инициализатор в любой из его подклассов.

protocol TestProtocol {
    init()
}

class TestClass: TestProtocol {
    required init() {

    }
}

здесь required ключевое слово должно присутствовать, потому что все подклассы TestClass также необходимо предоставить init() (потому что они также соответствовать TestProtocol).

наличие необходимого инициализатора позволяет инициализировать класс, не зная, что это такое во время компиляции, что полезно по целому ряду причин:

let classType: TestProtocol.Type = TestClass.self
let object = classType.init()

если ваш класс соответствует нескольким протоколам, каждый с другим инициализатором, например, каждый из этих инициализаторов также должен быть обязательным:

protocol OtherProtocol {
    init(thing: Int)
}

class OtherClass: TestClass, OtherProtocol {
    let thing: Int

    required init() { // Required from superclass/its protocol
        self.thing = 0
    }

    required init(thing: Int) { // Required from new protocol
        self.thing = thing
    }
}

обратите внимание, что добавление super.init() не требуется в этом специальном случае, потому что Swift будет автоматически включать вызов, если он не принимает никаких параметров.

во всех приведенных выше примерах инициализаторы обозначены, потому что они не включают convenience ключевое слово.

даже если у вас не было никаких протоколов, вы все равно можете использовать required на пример, тип класса, который не известен во время компиляции:

class BaseClass {
    let value: Int

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

class SubClass: BaseClass {
    required init(value: Int) { // Required from superclass
        super.init(value: value) // Must call desginated initialiser of superclass
    }
}

let someBaseClassType: BaseClass.Type = SubClass.self
let someBaseClassInstance = someBaseClassType.init(value: 1)

Места Initialisers

A места инициализатор - это тот, который не является инициализатором удобства (i.e, маркированный с convenience). Назначенный инициализатор должен убедиться, что все свойства класса имеют значение до завершения инициализатора (или вызывается супер инициализатор). Инициализаторы удобства только не имеют этого требования, потому что они сами должны вызвать назначенный инициализатор.

class OtherSubClass: BaseClass {
    convenience required init(value: Int) {
        self.init() // Must call designated initialiser of this class
    }

    init() {
        super.init(value: 0) // Must call designated initialiser of superclass
    }
}

(это довольно надуманный пример.)

по моему опыту, инициализаторы удобства редко полезны, и я склонен находить проблемы, которые они решают, можно решить с помощью необязательные аргументы на Вместо места initialisers. Необходимо также учитывать тот факт, что инициализаторы не могут вызывать инициализаторы удобства в своем суперклассе, поэтому убедитесь, что у вас нет каких-либо удобных инициализаторов, которые обеспечивают функциональность, которую ваши назначенные инициализаторы не делают, если вы хотите, чтобы ваш класс был подклассом!


структуры и перечисления, не используйте required или convenience ключевые слова потому что эти слова используются для обозначения правила инициализации для подклассов, которые только classподдержка es:required ключевое слово указывает, что подклассы должны предоставить этот инициализатор и convenience ключевое слово указывает, что подклассы не могут вызвать этот инициализатор. Несмотря на отсутствие ключевых слов, они все равно должны предоставлять инициализаторы, определенные в любых протоколах, которым они соответствуют, и вы можете написать "удобные" инициализаторы, которые вызывают self.init, только без convenience ключевое слово.


ответить к вашему заявления:

  • необходимые инициализаторы не должны быть назначены.
  • места initialisers не требуется.
  • классы могут иметь несколько обязательных и назначенных инициализаторов.