Swift:为什么我不能从override init调用方法?

sna*_*ggs 5 swift

我有以下代码示例(来自PlayGround):

class Serializable : NSObject{
override init() { }
}

class Device : Serializable{

    var uuid:String

    override init() {

        println("init ")

        self.uuid = "XXX"

       self.uuid = Device.createUUID()

        println(self.uuid)

    }

   class func createUUID() -> String{
       return "XXX2"
    }
}


var device = Device()
Run Code Online (Sandbox Code Playgroud)

您可以注意到我将createUUID方法实现为静态.

但为什么我init不能以静态方式调用此方法?:

class Serializable : NSObject{
override init() { }
}

class Device : Serializable{

    var uuid:String

    override init() {

        // tried
        // super.init()

        println("init ")

        self.uuid = "XXX"

       self.uuid = self.createUUID() //  ERROR
       self.uuid = createUUID() // ERROR

        println(self.uuid)

        // tried
        // super.init()

    }

  func createUUID() -> String{
       return "XXX2"
    }
}


var device = Device()
Run Code Online (Sandbox Code Playgroud)

没有继承它可以正常工作:

class Device {

    var uuid:String

     init() {

        println("init ")

        self.uuid = "XXX"

       self.uuid = self.createUUID()

        println(self.uuid)

    }

    func createUUID() -> String{
       return "XXX2"
    }
}


var device = Device()
Run Code Online (Sandbox Code Playgroud)

Jef*_*mas 9

有两个竞争初始化安全检查导致您的问题.

安全检查1

指定的初始值设定项必须确保在委托一个超类初始化程序之前初始化其类引入的所有属性.

安全检查4

初始化程序无法调用任何实例方法,读取任何实例属性的值,或者在初始化的第一阶段完成之后将self作为值引用.

下面是它的工作原理.

override init() {
    super.init() // Fails safety check 1: uuid is not initialized.
    uuid = createUUID()
}
Run Code Online (Sandbox Code Playgroud)

反过来,

override init() {
    uuid = createUUID() // Fails safety check 4: cannot call an instance method before initialization is complete.
    super.init()
}
Run Code Online (Sandbox Code Playgroud)

感谢@Ruben的回答


cjw*_*rth 5

在Swift中通过继承进行初始化有点棘手。您必须先实例化所有子对象的实例变量,然后才能调用super.init(),但是需要先调用,super.init()然后才能调用该self对象上的方法。

我的建议是uuid在调用之前提供一个临时值super.init(),然后再uuid使用实例方法生成:

class Device : Serializable{

    var uuid:String

    override init() {
        // First you need to initialize this classes instance variables
        // This feels a little silly to put in a temporary value, but if you don't want to use an optional, then it is necessary
        self.uuid = ""

        // Next you need to initialize super before you can use the `self` object
        super.init()

        // Since you are calling `createUUID()`, you are calling an instance method on the `self` object
        // Your object must call `super.init()` before you can do so
        self.uuid = self.createUUID()
    }

    func createUUID() -> String{
        return "XXX2"
    }
}
Run Code Online (Sandbox Code Playgroud)

是在Swift中初始化从其他类继承的类的参考。它很长,但是您可以将其总结为:

override init() {
    // Make sure all instance variables for the child class are instantiated
    super.init()
    // Do other initialization that requires the `self` object here
}
Run Code Online (Sandbox Code Playgroud)

但是您也可以在那里阅读便利初始化程序,这非常方便。


Gre*_*zek 5

这就是为什么存在隐式展开的Optionals的原因。

“首先在定义了可选对象的值后立即确认该可选对象的值存在,并且可以肯定地认为此后的每个点都存在,则隐式展开的可选对象很有用。Swift中隐式展开的可选对象的主要用法是在类初始化期间(...)”

摘自:Apple Inc.“ Swift编程语言(Swift 3)”。iBooks。https://itun.es/gb/jEUH0.l

您需要做的就是隐式解包uuid:

class Device: Serializable {

    var uuid: String!

    override init() {
        super.init()
        self.uuid = createUUID()
    }

    func createUUID() -> String {
        return "XXX2"
    }
}
Run Code Online (Sandbox Code Playgroud)