0

Forgive me, I might have asked this before, but it hit me in a different manner, and am still learning Swift

In my main scene I can easily initialize a node and then manipulate it as I like:

let myGSlot = SKSpriteNode(color : .green, size: CGSize(width: 100.0, height: 100.0))

However when I try to subclass it:

    class GuessSlot : SKSpriteNode{
        init(color: SKColor, size: CGSize) {
            super.init()
    }
   required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
}

No matter what I do, the editor gives me many errors. The main one being:

Must call a designated initializer of the superclass 'SKSpriteNode' Whether I put it in init() or super.init()

I know I'm new to Swift, but this is killing me!

********* latest update and the only way I can get it to compiles but still crashes with the error:

Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffeec64aff0)

In the debugger I can see that zero values are coming in for the parameters

convenience init(color: SKColor, size: CGSize) {
        self.init(color: color, size: size)
        }

I do feel less stupid when I see all the threads out there with confusion over this info

creating an SKSpriteNode that's not subclassed

Caractacus
  • 83
  • 7
  • Init() is not available on an SkSpriteNode. You need use a different init. It has been a while since I have used SpriteKit. But I believe if you override the init with texture color and size, you will get all the convenience inits like color and size for free – Knight0fDragon Sep 06 '20 at 04:04
  • @Knight0fDragon But I have no texture for this. And according to the documentation, the init I am using, color & size, are still a valid init. – Caractacus Sep 06 '20 at 06:22
  • 1
    That is a convenience init https://developer.apple.com/documentation/spritekit/skspritenode/1519812-init , you need to pass nil to texture – Knight0fDragon Sep 06 '20 at 07:59
  • @Knight0fDragon I'm going to blame Apple's Docs for this. It showed the use of just color and size as valid. And maybe I'll take some of the blame for at least not trying to pass a nil to texture. – Caractacus Sep 08 '20 at 01:10
  • I see nothing wrong with apple docs? Color and size is a valid convenience init. If you override the one I gave you, and the required, you get all convenience for free. – Knight0fDragon Sep 08 '20 at 18:10
  • @Knight0fDragon I tried every which way. And the only way I could compile it is at the bottom of my OP. I have found so many threads on this topic. But please if you know the exact syntax I would love it. Something about passing a nil still makes me uncomfortable. – Caractacus Sep 10 '20 at 02:31
  • This latest update is looping on itself – Knight0fDragon Sep 11 '20 at 03:38

2 Answers2

1

In Swift, you need to call an initializer that is implemented directly from your super class, in this case, SKSpriteNode. super.init() is implemented by another class that is in SKSpriteNode's inheritance tree, like SKNode or NSObject. You can always check the documentation for which constructors can you call for each class. It's very important to pay understand that you need to call designated initializers in your subclass

For example, you can do

class GuessSlot : SKSpriteNode{
   init(color: SKColor, size: CGSize) {
       super.init(texture: nil, color: color, size: size)
   }

   required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
   }
}
Pastre
  • 684
  • 8
  • 17
  • Put a latest update in my OP. Was the only way I could compile, but it crashed. I tried your example, but only got errors when I tried **override** or **super**. Convenience initializer for 'GuessSlot' must delegate, for one – Caractacus Sep 06 '20 at 06:18
  • My bad, didn't see that `init(color: SKColor, size: CGSize)` is a `convenience`. Check this out https://stackoverflow.com/questions/24122421/why-cant-swift-initializers-call-convenience-initializers-on-their-superclass – Pastre Sep 06 '20 at 14:57
  • 1
    @Caractacus updated my example, it should work now :) – Pastre Sep 06 '20 at 15:08
  • I'm going to blame Apple's Docs for this. It showed the use of just color and size as valid. And maybe I'll take some of the blame for at least not trying to pass a nil to texture. – Caractacus Sep 08 '20 at 01:10
0

I am not sure where the disconnect is, but as mentioned in the comments, you just needed to override the proper designated init texture, color,size.

class TestSpriteNode : SKSpriteNode{
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    override init(texture: SKTexture?, color: UIColor, size: CGSize) {
        super.init(texture: texture,color:color,size:size)
    }
}

This will get you access to all of the inits of your parent class.

You will now be able to do var s = TestSpriteNode(color:.red,size:CGSize(width:1,height:1))

If you need to override this convenience init, you need to refer to one of the designated inits you overrode, not the convenience init.

class TestSpriteNode : SKSpriteNode{
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    override init(texture: SKTexture?, color: UIColor, size: CGSize) {
        super.init(texture: texture,color:color,size:size)
    }
    
    convenience init(color: UIColor, size: CGSize) {
        self.init(texture: nil,color:color,size:size)
    }
    
}
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • I was trying to do it without the texture, since there is no texture. And the Apple docs showed the use of just color and size as valid init. – Caractacus Sep 11 '20 at 02:04
  • Again, where is the disconnect? This is clearly doing it without the texture. – Knight0fDragon Sep 11 '20 at 03:20
  • Do you have trouble understanding what a convenience init is over a designated init? – Knight0fDragon Sep 11 '20 at 03:36
  • The disconnect is this: I can create it outright (not subclassing it) by passing only color and size. I didn't have to include texture at all. So I was trying to do the same in a subclass. But I couldn't find a way to pass just those two in the subclass. – Caractacus Sep 11 '20 at 03:40
  • This does that. If you override 1 designated init, you have to override them all to get the convenience inits. So either remove all inits, or do what I am doing. You can’t override a convenience init, those are fake inits to provide you with a convenient way to create an object. Like say you do not want to pass nil to texture, you create a convenience init that does it for you (which is what Apple does) – Knight0fDragon Sep 11 '20 at 03:43
  • I guess we're just mis-communicating, and I am new to swift. I added a screenshot to the OP. Since Swift offered me a choice that didn't involved the word texture, I thought the subclass would be the same. Hope this clears this up what I was thinking when I asked for help – Caractacus Sep 11 '20 at 04:11
  • Do you understand now what is going on? Your subclass does give you a choice without texture, it all comes down to designated inits. Override all or override none. Override some is not an option with convenience inits. – Knight0fDragon Sep 11 '20 at 04:12
  • Yes I really do. I hope the picture helps explains why I thought the word texture never even needed to be typed. – Caractacus Sep 11 '20 at 04:14
  • Not really, unless you think that picture is showing all designated inits. – Knight0fDragon Sep 11 '20 at 04:16