gpt4 book ai didi

swift - 必需的初始化器和指定的初始化器有什么区别?

转载 作者:IT王子 更新时间:2023-10-29 05:30:01 24 4
gpt4 key购买 nike

我正在创建自己的自定义 tableViewCell,然后收到一条错误消息:

'required' initializer 'init(coder:)' must be provided by subclass of'UITableViewCell'

我查了一下,显然也必须实现它。但这导致我对必需的和指定的初始化器感到困惑

Apple Docs说:

必需的初始化程序:

Write the required modifier before the definition of a classinitializer to indicate that every subclass of the class mustimplement that initializer:

指定初始化器

Designated initializers are the primary initializers for a class. Adesignated initializer fully initializes all properties introduced bythat class and calls an appropriate superclass initializer to continuethe initialization process up the superclass chain.

下列说法正确的是:

  • 必需的初始化器总是指定的初始化器
  • 每个指定的初始化程序都不一定是必需的初始化器
  • 一个类只能有一个必需的初始化器,但是它可以有多个指定的初始化器?

话虽如此,我仍然不完全理解它们的功能差异。

最佳答案

必需的初始化器和指定的初始化器并没有真正相关,尽管相关的关键字 requiredconvenience 都用于指定对子类的限制。

必需的初始化器

必需 初始化程序保证您可以使用该初始化程序初始化一个类型或其任何子类型。如果你在协议(protocol)中有一个初始化程序并且你符合该协议(protocol),你必须使用 required (如果它是一个类)因为该协议(protocol)保证初始化程序存在于该类中,并且任何它的子类。当您在类的初始化程序上使用 required 时,这表明它的所有子类也可以使用该方法进行初始化。这意味着您还需要将该初始化程序添加到它的任何子类中。

protocol TestProtocol {
init()
}

class TestClass: TestProtocol {
required init() {

}
}

这里,required 关键字必须存在,因为 TestClass 的任何子类也必须提供 init()(因为它们也符合 TestProtocol).

拥有一个必需的初始化程序允许您在编译时不知道它是什么的情况下初始化一个类,这出于多种原因很有用:

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

如果您的类符合多个协议(protocol),例如每个协议(protocol)都有不同的初始化程序,则还必须要求每个初始化程序:

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 关键字。

即使您没有任何协议(protocol),您仍然可以通过初始化一个在编译时未知的类的类型来使用 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)

指定初始化器

designated 初始化器不是便利初始化器(即标记有convenience)。指定的初始化器必须确保类的所有属性在初始化器完成(或调用 super 初始化器)之前都具有值。便利初始化器没有此要求,因为它们必须自己调用指定的初始化器。

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 can't call convenience initialisers on their superclass ,因此请确保您没有任何方便的初始化程序,如果您打算对您的类进行子类化,则这些初始化程序提供的功能是您指定的初始化程序所不具备的!


结构和枚举不使用requiredconvenience 关键字,因为这些关键字都用于指示子类的初始化规则,只有classes支持:required关键字表示子类必须提供那个初始化器,convenience关键字表示子类不能调用那个初始化器。尽管没有关键字,它们仍然必须提供在它们遵循的任何协议(protocol)中定义的初始化程序,并且您可以编写调用 self.init 的“方便”初始化程序,只是没有 convenience 关键字。


回应您的陈述:

  • 不需要指定必需的初始化器。
  • 不一定需要指定的初始化程序。
  • 类可以有多个必需的和指定的初始化程序。

关于swift - 必需的初始化器和指定的初始化器有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41596785/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com