我正在创建自己的自定义tableViewCell然后我得到一个错误说:
'required'initulator'init(coder :)'必须由'UITableViewCell'的子类提供
我查了一下,显然这也是实现它的必要条件.但这导致我对必需与指定初始化器的混淆
Apple Docs说:
必需的初始化器:
在定义类初始值设定项之前编写必需的修饰符,以指示该类的每个子类都必须实现该初始化程序:
指定的初始化程序
指定的初始值设定项是类的主要初始值设定项.指定的初始化程序完全初始化该类引入的所有属性,并调用适当的超类初始化程序以继续超类链的初始化过程.
以下陈述是否正确:
必需的初始化程序始终是指定的初始化程序
每个指定的初始化程序不一定是必需的初始化程序
一个类只能有一个必需的初始值设定项,但它可以有多个指定的初始值设定项?
话虽如此,我仍然不完全理解他们的功能差异.
所需initialisers和指定initialisers没有多大关系,但相关的关键字required
,并convenience
均用于指定子类的限制.
一个需要初始化器作担保,你可以初始化一个类型,或任何其子类型中,与初始化器.如果您在协议中有一个初始化器并且您符合该协议,则必须使用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)指定的初始化者
甲指定初始化剂是一个其不是方便初始化剂(即,标有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 } }
(这是一个相当人为的例子.)
根据我的经验,便利初始化器很少有用,我倾向于发现他们解决的问题可以使用指定初始化器上的可选参数来解决.还需要考虑这样一个事实,即初始化者不能在其超类上调用便利初始化者,因此请确保您没有任何便利初始化者,如果您打算将您的类划分为子类,则该初始化者将提供您指定的初始化者不具备的功能!
结构和枚举不使用required
或convenience
关键字,因为这些关键字都用于指示子类的初始化规则,仅class
支持:required
关键字指示子类必须提供该初始化,并且convenience
关键字指示子类不能调用该初始化.尽管没有关键字,但它们仍然必须提供在其符合的任何协议中定义的初始化程序,并且您可以编写"方便"的初始化程序self.init
,只需不使用convenience
关键字即可调用.
回应你的陈述:
不必指定所需的初始化程序.
不必要求指定的初始化程序.
类可以有多个必需和指定的初始化程序.