当 init() 还初始化成员变量并引用“self”时,将 super.init() 放在哪里
Posted
技术标签:
【中文标题】当 init() 还初始化成员变量并引用“self”时,将 super.init() 放在哪里【英文标题】:Where to put super.init() when init() also initializes member variable and references "self" 【发布时间】:2016-10-05 07:34:18 【问题描述】:我正在学习 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 中创建一个虚拟初始化程序(零参数)并调用它:
var spriteComponent = SpriteComponent()
为了在引用“self”之前调用 super.init()
谁能解释我为什么要跳这种愚蠢的踢踏舞?肯定有更好的方法来做到这一点吗? Swift 不可能是 *&%&/(% 对吗?
【问题讨论】:
尝试改用var spriteComponent : SpriteComponent!
好的,那么似乎有解决方案。来自 Java/C# 等,如果没有另外指定,我习惯于初始化为 null 的变量。我可以忍受将其初始化为零。我仍然对所有这些都不满意?和 ! 在 Swift 中..
@PeterAnderson !和 ?一旦你掌握了符号,它就非常简单,所以如果一个变量没有任何变量,那意味着它根本不能为 nil,所以基本上它不能有一个空值开始。 !
意味着一开始可以是空的,但是一旦分配它就不能再为 nil(如果你尝试在它最初仍然为 nil 时访问它,应用程序将崩溃),?
基本上就像一个普通的 java变量可以存放任何东西,但是在您可以访问它之前,您必须始终“解包”它,这基本上意味着在使用它之前确保它不为零,例如if let x = OptionalVariable
好的谢谢解释。但是访问后来在init()
中构造的成员var node : EntityNode!
仍然给我"Value of optional type 'EntityNode?" not unwrapped;..."
【参考方案1】:
您必须先初始化子类中声明的所有非可选属性,然后才能调用 super.init()
所以你有两种方法可以解决这些问题:
-
将属性类型更改为可选(
SpriteComponent?
或 SpriteComponent!
)。
在声明每个属性时或在调用 super.init 之前在初始化程序中初始化每个属性
在您的情况下,第一个选项更适合。
您可以在此处找到有关 Swift 两阶段初始化的更多信息: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html
本教程也可能会有所帮助:(向子类添加属性段落): https://www.raywenderlich.com/121603/swift-tutorial-initialization-part-2
【讨论】:
【参考方案2】:必须在创建对象之前初始化所有非可选属性。将您的属性设为可选。
【讨论】:
【参考方案3】:spriteComponent
是一个非可选变量。因此必须在调用super.init
之前对其进行初始化(解释第一个提到的错误)。
你不能通过稍后调用super.init
来解决这个问题,因为SpriteComponent
的构造函数需要对self的引用,只有调用super.init
后才能使用。 (解释第二个错误)
作为一种解决方案,您可以将 spriteComponent
设为未包装的可选:
var spriteComponent : SpriteComponent!
这指示编译器允许spriteComponent
不被初始化,并让您有责任在以后自己做。
【讨论】:
【参考方案4】:这种“踢踏舞”是有原因的。 在swift中,类初始化是一个两阶段的初始化:
第 1 阶段 - 所有存储的属性都由定义它们的类赋予一些初始值(nil 也可以)
第 2 阶段 - 现在每个类都可以更改初始值并使用 self
这是为什么呢?安全为主 - 在第 2 阶段了解所有属性都有一些价值。
因此,在您的代码中,您可能不需要一个空的虚拟初始化程序,但将您的 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")
【讨论】:
以上是关于当 init() 还初始化成员变量并引用“self”时,将 super.init() 放在哪里的主要内容,如果未能解决你的问题,请参考以下文章
python中__init__()括号里面的变量应该如何写,分别表示啥?