swift 初始化器在调用super.init前使用self的问题

swift文档里说在完成所在类和所有父类的属性初始化后,才能使用self,也就是初始化器调用super.init后才能使用self

class Movie: Media {
    
    var myString: String
    init(frame: CGFloat) {
        
        self.myString = "11"
        print(self.myString)
        print(self)

        super.init()
        print(self)
        print("2")
    }
}

比如这段代码,print(self)会报错说要在super.init()后才能调用,但是print(self.myString)却能正常使用。这是为什么?

阅读 14.9k
2 个回答

print(self)会报错的原因是编译器检测到并提示错误'self' used before super.init call
print(self.myString)没有报错的原因是,编译器没有处理这种特殊情况。

class test1: NSObject {
    var name:String?
    override init() {
        self.name = "123";
        
        super.init()
    }
}

class test2: test1 {
    var age :Int = 0
    override init() {
        self.name = "123";
        self.age = 10
        
        super.init()
        
    }
}

你可以看一下这段代码,test1的self.name = "123";不会报错但是test2的会,区别是test1中调用name是自己的属性,而test2调用的是父类的属性。我猜想:swift中在init方法里,self已经是被构建出来了的,即已经有了内存,然后你设置自身属性,它是可以被赋值的;但是没有调用super.init()之前,父类的内存没有被创建,那么你设置父类的属性是没法操作的;print(self)也不可用估计是print方法也需要父类的属性吧。

我还得去找下文档验证下。

//更新
文档在Initialization中的Two-Phase Initialization那一部分,里面有关于init方法的4个检测。

  • 第一点就说了,要先把stored property赋值好了,才可以调父类的init.let类型属性要么有默认值,要么在init方法内指定,而var的可变属性,默认值就是nil啦,所以没有默认值的let属性就必须在init里先赋值。

A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.”

  • 至于print(self)不能使用在super.init之前应该是第4点里说的:

An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.

注意我加粗的后半句,在第一阶段前不能使用self作为值使用,print函数把self传入就是把self当值使用了吧。第一阶段的解释最后一句:

Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.

意思就是继承链所有的stored properties都赋值了,才算结束。所以要先调用super才可以。如果是一个没有父类的类,调用print(self)就没有问题。

class test1 {
    let name:String
    init() {
        name = "1"
        print(self);
    }
}

最后,关于内存方面的猜想没有找到文档。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进