Ios 当init()还初始化成员变量并引用时,将super.init()放在何处;“自我”;

Ios 当init()还初始化成员变量并引用时,将super.init()放在何处;“自我”;,ios,swift,swift2,swift3,Ios,Swift,Swift2,Swift3,我正在学习Swift,现在我有了以下代码: import SpriteKit import GameplayKit class Player: GKEntity { var spriteComponent : SpriteComponent init(imageName: String) { super.init() // gives error: self.spriteComponent not initialized at super.init call let tex

我正在学习Swift,现在我有了以下代码:

import SpriteKit
import GameplayKit

class Player: GKEntity {

var spriteComponent : SpriteComponent

init(imageName: String) {
    super.init() // gives error: self.spriteComponent not initialized at super.init call
    let texture = SKTexture(imageNamed:  imageName)
    spriteComponent = SpriteComponent(entity: self, texture: texture, size:  texture.size())

    // super.init() Placing it here gives error on line above: "self used before super.init() call"
    addComponent(spriteComponent)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

}
我已经看到了关于这一点的其他问题,但我无法想象我必须在SpriteComponent中创建一个虚拟初始值设定项(具有零args)并这样调用:

var spriteComponent = SpriteComponent()
为了在引用“self”之前调用super.init()


有人能解释我为什么要跳这种愚蠢的踢踏舞吗?一定有更好的方法做对了吧?斯威夫特不可能是那样的*&%&/(%对吗?

所有非可选属性必须在创建对象之前进行初始化。将属性设置为可选属性。

所有非可选属性必须在创建对象之前进行初始化。将属性设置为可选属性。

spriteComponent
是非可选变量。因此,必须在创建对象之前对其进行初始化调用super.init(解释第一个提到的错误)

稍后调用
super.init
无法解决此问题,因为
SpriteComponent
的构造函数需要对self的引用,而self只有在调用
super.init
后才可用(解释第二个错误)

作为一种解决方案,您可以将
spriteComponent
作为一个展开的可选组件:

var spriteComponent : SpriteComponent!

这指示编译器允许不初始化
spriteComponent
,并让您有责任在以后的时间点自己进行初始化。

spriteComponent
是一个非可选变量。因此,必须在调用
super.init
之前对其进行初始化(解释了第一个提到的错误)

稍后调用
super.init
无法解决此问题,因为
SpriteComponent
的构造函数需要对self的引用,而self只有在调用
super.init
后才可用(解释第二个错误)

作为一种解决方案,您可以将
spriteComponent
作为一个展开的可选组件:

var spriteComponent : SpriteComponent!
这指示编译器允许不初始化
spriteComponent
,并让您有责任在以后的某个时间点自己进行初始化。

这种“踢踏舞”是有原因的。 在swift中,类初始化分为两个阶段:

阶段#1-所有存储的属性都由定义它们的类给出一些初始值(nil也可以)

阶段#2-现在每个类都可以更改初始值并使用self

这是为什么?安全主要是——在第二阶段知道所有属性都有一些值

因此,在您的代码中,您可能不需要空的虚拟初始值设定项,但将您的sprite组件转换为可选组件可能很方便:

class Player: GKEntity{
var spriteComponent : SpriteComponent? = nil  // optional

init(imageName: String)
{
    super.init() // now OK

    let texture = SKTexture(imageNamed:  imageName)
    spriteComponent = SpriteComponent(entity: self, texture: texture, size:  texture.size())!
    addComponent(spriteComponent!)  // unwrap here
}
required init?(coder aDecoder: NSCoder)
{
    fatalError("init(coder:) has not been implemented")
}
}这种“踢踏舞”是有原因的。 在swift中,类初始化分为两个阶段:

阶段#1-所有存储的属性都由定义它们的类给出一些初始值(nil也可以)

阶段#2-现在每个类都可以更改初始值并使用self

这是为什么?安全主要是——在第二阶段知道所有属性都有一些值

因此,在您的代码中,您可能不需要空的虚拟初始值设定项,但将您的sprite组件转换为可选组件可能很方便:

class Player: GKEntity{
var spriteComponent : SpriteComponent? = nil  // optional

init(imageName: String)
{
    super.init() // now OK

    let texture = SKTexture(imageNamed:  imageName)
    spriteComponent = SpriteComponent(entity: self, texture: texture, size:  texture.size())!
    addComponent(spriteComponent!)  // unwrap here
}
required init?(coder aDecoder: NSCoder)
{
    fatalError("init(coder:) has not been implemented")
}

}

在调用super.init()之前,必须初始化子类中声明的所有非可选属性

因此,您有两种解决此类问题的方法:

  • 将属性类型更改为可选(或
    SpriteComponent?
    SpriteComponent!
  • 在声明每个属性时或在调用super.init之前在初始值设定项中初始化每个属性
  • 在你的情况下,第一种选择更合适

    您可以在此处找到有关Swift两阶段初始化的更多信息:

    本教程也可能有帮助:(将属性添加到子类段落):

    在调用super.init()之前,必须初始化子类中声明的所有非可选属性

    因此,您有两种解决此类问题的方法:

  • 将属性类型更改为可选(或
    SpriteComponent?
    SpriteComponent!
  • 在声明每个属性时或在调用super.init之前在初始值设定项中初始化每个属性
  • 在你的情况下,第一种选择更合适

    您可以在此处找到有关Swift两阶段初始化的更多信息:

    本教程也可能有帮助:(将属性添加到子类段落):

    尝试使用
    var-spriteComponent:spriteComponent!
    insteadOK,似乎有解决方案。来自Java/C等,我习惯于将变量初始化为null,如果没有其他指定的话。我可以自己将其初始化为nil。我仍然无法与Swift中的所有“and!”混淆。@PeterAnderson!and?n一旦掌握了窍门,旋转就非常简单,所以如果一个变量没有,这意味着它根本不能为零,所以基本上它不能有空值开始。
    意味着它可以为空开始,但一旦赋值,它就再也不能为零了(如果您试图在初始状态为零时访问它,应用程序将崩溃),
    基本上就像一个普通的java变量,但在访问它之前,您必须始终“展开”这基本上意味着在使用它之前确保它不为零,例如,如果让x=OptionalVariable或
    optionalVariabe?.someMethod()
    someMethod()
    如果
    OptionalVariable
    为零,则不会执行,这是一种简单的空检查,这是这个可选内容的重要部分)好的,谢谢解释。但是访问后来在
    init()
    中构造的成员
    var node:EntityNode!
    仍然会给我
    “可选类型'EntityNode'的值”未展开;。。。“
    尝试使用
    var-spriteComponent:spriteComponent!
    insteadOK似乎有解决方案。来自Java/C#etc的我被用于初始化为null的变量,如果没有另外指定。I