【问题标题】:Is setting of non-optional ivars demanded in all init methods?所有初始化方法都需要设置非可选的 ivars 吗?
【发布时间】:2014-06-18 15:17:48
【问题描述】:

我正在尝试创建一个SKSpriteNode 子类。计划是让它在内部处理大部分设置,但令人讨厌的是,这似乎会强制执行相当多的代码重复,特别是在设置非可选的 ivars 和常量时。

class TrollSpriteRegular : SKSpriteNode{
    let head : SKSpriteNode
    let body : SKSpriteNode

    init(){
        head = SKSpriteNode(color: SKColor.orangeColor(), size: CGSizeMake(60, 60))
        body = SKSpriteNode(color: SKColor.purpleColor(), size: CGSizeMake(40, 60))
        super.init()
    }

    // Desginated intiallizer
    init(texture: SKTexture!, color: UIColor!, size: CGSize) {
        head = SKSpriteNode(color: SKColor.orangeColor(), size: CGSizeMake(60, 60))
        body = SKSpriteNode(color: SKColor.purpleColor(), size: CGSizeMake(40, 60))
        super.init(texture: texture, color: color, size: size)
    }
}

如果我尝试从两个初始化程序之一中删除头或主体的创建,则会导致编译器错误并且我无法构建。有什么办法可以避免这种情况,还是上述模式不是特别快速友好?

我“需要”init 方法以允许通过使用 let trollSprite = TrollSpriteRegular() 创建新实例。


编辑:好的,可以通过在声明常量时定义常量来简化上述内容。

class TrollSpriteRegular : SKSpriteNode{
    let head = SKSpriteNode(color: SKColor.orangeColor(), size: CGSizeMake(60, 60))
    let body = SKSpriteNode(color: SKColor.purpleColor(), size: CGSizeMake(40, 60))
...

但是,如果我添加一个应该通过 init 方法实际接收其值的变量,我将遇到同样的问题。例如:

let trollName : String

init(name :String){ 
    trollName = name
    super.init(texture: nil, color: nil, size: CGSizeZero)
}

这将迫使我在我自己的init(name:) 和指定的初始化程序中定义 trollName。哦,好吧。

【问题讨论】:

  • SKSpriteNode指定的init是什么?你应该只调用我相信的超类的指定初始化器
  • 指定的初始化器是init(texture:color:size),但它不是特别适合我的子类。当我本可以摆脱et trollSprite = TrollSpriteRegular() 时,不得不打电话给let troll = TrollSpriteRegular(texture: nil, color: nil, size: CGSizeZero) 似乎不必要的麻烦但如果那是探戈的方式,我想我必须屈服......

标签: initialization sprite-kit swift subclassing


【解决方案1】:

需要一个指定的初始化器来初始化所有类的状态。在便利构造器中,您可以将该职责委托给指定的构造器。

但是,在您的情况下,您似乎需要两个指定的初始化程序。但是由于这些变量的值不依赖于初始化程序的任何输入,因此您可以在它们的声明中定义它们的值。这是该类的重复性较低的版本:

class TrollSpriteRegular : SKSpriteNode {
    let head : SKSpriteNode = SKSpriteNode(color: SKColor.orangeColor(), size: CGSizeMake(60, 60))
    let body : SKSpriteNode = SKSpriteNode(color: SKColor.purpleColor(), size: CGSizeMake(40, 60))
}

【讨论】:

  • 它仍然看起来很笨重,如果我想添加通过他们自己的初始化程序创建的其他(类似属性的)ivars,我 必须 在指定的初始化程序和我自己的,对吧?
  • @nickfalk:我不太清楚你的意思。您想要创建的任何不依赖于输入初始化器的值都可以通过这种方式定义。如果它确实依赖于初始化器的输入,那么所有指定的初始化器都必须定义它——但需要许多指定的初始化器是不正常的。很多时候你可以只写一个然后让其他的方便初始化。
  • 嗯,我想我可能会遗漏一些东西:当我将 SKSpriteNode 子类化时,我必须 include 父类中指定的初始化程序,即使它没有参数所需的变量。包含它时,需要设置要编译的应用程序的变量。
  • 从 Storyboard 加载的类(例如 VC)呢?覆盖指定的 init 并设置额外的 ivars 是一种好习惯吗?
  • @HariKaramSingh:Outlets 始终是可选的,特别是因为在初始化程序中担心它们是不切实际的。
【解决方案2】:

考虑到非可选变量不能为零,这种行为是可以预料的。如果您正在寻找一种更简洁的方法,您可以使用默认值(颜色和大小)对变量进行内联初始化。然后,如果您碰巧有一个需要更改其中一个值的初始化程序,您可以直接更改精灵的颜色或大小属性的值。

class TrollSpriteRegular: SKSpriteNode {
    let head = SKSpriteNode(color: SKColor.orangeColor(), size: CGSizeMake(60.0, 60.0))
    let body = SKSpriteNode(color: SKColor.purpleColor(), size: CGSizeMake(40.0, 60.0))

    ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 2020-11-23
    • 1970-01-01
    相关资源
    最近更新 更多