2
votes

I have been trying to override the SKSpriteNode initializer with a convenience initializer that allows me to instantiate an SKSpriteNode child with a few extra properties, but every time I try, I keep getting compiler errors. These are the two big rules as I understand.

Rules:

  1. Every convenience initializer must reference a designated initializer, whether it be from the class itself or the parent class
  2. Subclass properties must be set before an initializer delegates to the parent.

Here is my code which I believe follows the rules:

class WalkingMonster: SKSpriteNode {
    var rangeOfMovement: CGFloat
    var originalPosition: CGFloat
    var platformNumber: Int
    var imageName = "walkingAlien"
    var sizes = [CGSize(width: CGFloat(30.0), height: CGFloat(30.0)), CGSize(width: CGFloat(30.0), height: CGFloat(15.0)), CGSize(width: CGFloat(30.0), height: CGFloat(7.0))]

    override init(texture: SKTexture?, color: UIColor, size: CGSize) {
        super.init(texture: texture!, color: color, size: size)
    }

    convenience init(texture: SKTexture, color: UIColor, size: CGSize, rangeOfMovement: CGFloat, originalPosition: CGFloat, platformNumber: Int) {
        self.rangeOfMovement = rangeOfMovement
        self.originalPosition = originalPosition
        self.platformNumber = platformNumber
        self.init(texture: texture, color: color, size: size)
    }
}

I am told by the compiler to implement the following required init that will just throw an error:

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

When I implement it, I get an error saying that self.rangeOfMovement is not initialized at super.init() call and the use of self in delegating initializer before self.init is called. When I take the self out of the initializer, it treats each member variable as local variable to the function.

I have tried swapping the override init() call and using super.init() in the subclass convenience initializer.

class WalkingMonster: SKSpriteNode {
    var rangeOfMovement: CGFloat
    var originalPosition: CGFloat
    var platformNumber: Int
    var imageName = "walkingAlien"
    var sizes = [CGSize(width: CGFloat(30.0), height: CGFloat(30.0)), CGSize(width: CGFloat(30.0), height: CGFloat(15.0)), CGSize(width: CGFloat(30.0), height: CGFloat(7.0))]

    convenience init(texture: SKTexture, color: UIColor, size: CGSize, rangeOfMovement: CGFloat, originalPosition: CGFloat, platformNumber: Int) {
        self.rangeOfMovement = rangeOfMovement
        self.originalPosition = originalPosition
        self.platformNumber = platformNumber
        super.init(texture: texture, color: color, size: size)
    }

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

  }

I get an error saying convenience initializer for WalkingMonster must delegate with self.init rather than chaining to a superclass initializer with super.init(), which I had already tried implementing before with no success. I feel as though overriding initialization properties should be a pretty simple matter and I must be missing something. As always, any help, greatly appreciated

1

1 Answers

2
votes

The compiler is right: your override would be fine except that you haven't initialized your properties. If you need to have parameters to do that, then you'll need to create a new designated initializer instead: your init(texture: SKTexture, color: UIColor, size: CGSize, rangeOfMovement: CGFloat, originalPosition: CGFloat, platformNumber: Int) will do; simply remove convenience from it, as it is a new designated initializer, not a convenience initializer. (Convenience initializers, as the compiler points out, must delegate across to self.something, not up as you wish to do.)

As for init?(coder:), you're fine to use the fatalError version as long as you are never going to encode or decode instances of your subclass. If you do need to make use of NSCoding, then you'll need to provide a working implementation of init?(coder:) and override encodeWithCoder(_:), too.