3

我正在翻阅有关初始化程序和展开的 Swift 文档,但我无法理解有关其工作方式的一些基本知识。

目标:我想子类化SKShapeNode并使用let reverse : Bool来定义一个实例变量,该变量只在构造函数中设置并且永远不需要修改。这似乎是定义此类变量的正确方法,但这在下面的代码中会爆炸。

以下代码有效,即它可以编译,不会崩溃并获得我想要的行为。

public class BeamedNotesNode: SKShapeNode {

    var notes : [Note]!
    var noteNodes : [NoteNode]?
    var beam : BeamNode?
    var childBeams : [BeamNode]?
    var reverse : Bool?

    convenience public init(
        withTicks notes: [Note],
        reverse: Bool = false)
    {
        self.init(rect: CGRect(x: 0, y: 0, width: 1, height: 1))

        self.notes = notes
        self.reverse = reverse
        ...

但是,当我将其修改为 use 时let reverse : Bool,出现错误:Class 'BeamedNotesNode' has no initializers在编译时:

public class BeamedNotesNode: SKShapeNode {

    var notes : [Note]!
    var noteNodes : [NoteNode]?
    var beam : BeamNode?
    var childBeams : [BeamNode]?
    let reverse : Bool

    convenience public init(
        withTicks notes: [Note],
        reverse: Bool = false)
    {
        self.init(rect: CGRect(x: 0, y: 0, width: 1, height: 1))

        self.notes = notes
        self.reverse = reverse
        ...

看来我应该能够使用let并避免丑陋的强制解包实例变量。我如何在这里实现这一目标?

4

2 回答 2

1

问题是如果你有一个非可选的常量,你需要确保它也被指定的初始化器初始化。

如果您希望它表现得像非可选常量,最简单的解决方案是 (a) 为变量提供默认值;但是(b)制作setter private,即

private(set) var reverse = false

我知道这不是您正在寻找的东西,但在外部它的行为就像一个常量,但是您的便利初始化程序仍然可以使用作为参数提供的任何内容来覆盖该值。

于 2017-12-16T20:15:46.650 回答
0

这应该工作

public class BeamedNotesNode: SKShapeNode {

    var notes : [Note]!
    var noteNodes : [NoteNode]?
    var beam : BeamNode?
    var childBeams : [BeamNode]?
    let reverse : Bool

    public init(withTicks notes: [Note], reverse: Bool = false) {
        self.notes = notes
        self.reverse = reverse
        super.init()
    }

    public required init?(coder aDecoder: NSCoder) {
        self.reverse = false
        super.init(coder: aDecoder)
    }

}

这是怎么回事?

这里有一些关于初始化器的规则。

事实 #1

在向 中添加常量属性的那一刻BeamedNotesNode,编译器希望您提供指定的初始化程序(不是方便的初始化程序)来填充该常量属性。

事实 #2

但是由于您添加了指定的初始化程序,超类 ( SKShapeNode) 中的指定初始化程序在您的类之外不再可用。这使您的类不再符合NSCoding,因此您需要手动添加另一个初始化程序

public required init?(coder aDecoder: NSCoder) {
    self.reverse = false
    super.init(coder: aDecoder)
}

现在编译器很高兴。

注意事项

我强烈建议您避免在代码中强制解包值,除非您别无选择。

所以这

var notes : [Note]!

应该成为

var notes : [Note]?
于 2017-12-16T20:42:38.070 回答