【问题标题】:Why does calling super.init() call my default init()为什么调用 super.init() 调用我的默认 init()
【发布时间】:2025-12-29 03:40:11
【问题描述】:

所以我有一个带有指定初始化程序的类,它为每个存储的属性获取值。 我所有存储的属性也有一个默认值,所以我假设这个类有一个默认的 init。

在我指定的init中,我调用super.init()

问题是,如果我在初始化结束时调用它,它会将所有属性加载到默认值,但如果我在开始时调用它,它会按预期工作。

书上说:

安全检查 1 指定的初始化程序必须确保所有 其类引入的属性在其委托之前被初始化 直到一个超类初始化器。

如上所述,一个对象的内存只被认为是完全的 一旦其所有存储属性的初始状态被初始化 已知。为了满足这个规则,一个指定的 初始化器必须确保它自己的所有属性都被初始化 在它离开链条之前。

所以我不确定事情是否发生了变化或者我做错了什么?

代码:

class ORQuizViewController: UIViewController {
let imageView: UIImageView = UIImageView(image: nil)
let questionLabel: UILabel = UILabel()
let choicesArray: [BlackWhiteButton] = [BlackWhiteButton]()
let correctAnswer: Int = -1

init(image: UIImage!, question: String, choices: [String], answerIndex: Int) {
    super.init()
    imageView = UIImageView(image:image)
    questionLabel = UILabel()
    questionLabel.text = question
    var tempChoices = [BlackWhiteButton]()
    for choice in choices {
        var choiceLabel = BlackWhiteButton()
        choiceLabel.setTitle(choice, forState: .Normal)
        tempChoices.append(choiceLabel)
    }
    choicesArray = tempChoices
    correctAnswer = answerIndex
}

【问题讨论】:

  • 属性是这个类定义的还是继承自超类?
  • 它们是由这个类定义的,所以根据Apple的文档,我应该在调用super之前进行初始化。
  • 您的初始化程序是标记为方便还是指定初始化程序?
  • 为清晰起见添加了代码。应该回答你的问题。
  • 为什么要将值设置为默认值并且有一个指定的初始化器来设置默认值?

标签: ios ios7 swift


【解决方案1】:

正确的解决方案是在分配最终值之前调用super.init,正如您所观察到的。正如您所说,安全检查 1 要求在委派之前初始化子类引入的所有属性 - 这由您的默认分配处理。

在初始化过程的第 1 阶段应用安全检查 1。

然后进行初始化过程的第 2 阶段 -

第二阶段

从链的顶部向下工作,每个指定 链中的初始化程序具有自定义实例的选项 进一步。初始化器现在可以访问 self 并且可以修改它的 属性,调用它的实例方法,等等。最后,任何 链中的便利初始化器可以选择自定义 实例并与 self 一起工作。

因此您需要在第 2 阶段分配最终值。

文档有点不清楚,但您似乎应该继续使用 Objective C 中首先调用超类 init 的典型约定。

【讨论】:

    【解决方案2】:

    我假设这是Objective C,我不熟悉那种语言,但谈到面向对象编程语言的操作,构造函数/初始化器是并且必须从最小派生类调用到最大派生类, 和相反顺序的析构函数。

    这样想,如果基类是蛋糕,而你的派生类添加了糖衣,你不能在蛋糕被构造之前把糖衣放在适当的位置。

    至于书中语句的含义,在调用初始化时,如果虚函数已经指向派生类的功能,则必须在调用虚函数之前初始化类。

    在 C++ 和 C# 中,语言分配对象,初始化最小派生组件,将虚函数指向第一个派生类,然后构造它,等等。类不调用超类初始化器。

    我知道我没有回答您的问题,但也许这会帮助您找出答案。如果你要调用 super.init(),首先调用 super.init() 似乎是正确的做法。

    也许这就是答案:如果虚函数确实指向您的覆盖,它们必须这样做,但您必须调用 super.init(),那么您需要初始化数据成员以防调用虚函数,调用 super.init() 来初始化内部类,然后继续你的初始化过程。这对我来说听起来很不安全,但我认为没有其他方法可以工作。

    【讨论】:

    • 您的回答描述了一般 OOO 想法并理解您要说的内容,但我的问题专门针对 Swift,它的处理方式略有不同。
    最近更新 更多