0

I'm working on application using SpriteKit and I'm having trouble with NSCoding on a particular object (a GKComponent object). I'm using Swift 4.0 and iOS 11 in Build Settings. The application always crashes on the line (marked with //***) where I'm trying to decode the object. I've been using the same structure for encoding/decoding other objects and they seem to work fine. Not sure why it won't work with this particular GKComponent object.I've spent hours trying to resolve this issue but couldn't figure out why. Any help will be appreciated.

Thanks in advance!

  class ItemEntity: GKEntity {
      
      var name: String!
      var embeddedSpell: KnockbackComponent?

      //Other variables
       
      init(itemName: String) {
            super.init()
            name = itemName
            embeddedSpell = KnockbackComponent(anItem: self)
            addComponent(embeddedSpell!)
           
            //Other initializations
       }

       override func encode(with aCoder: NSCoder) {
           aCoder.encode(self.name, forKey: "Item.name")
           aCoder.encode(embeddedSpell, forKey: "Item.embeddedSpell")
           super.encode(with: aCoder)
       }
 
       required convenience init?(coder aDecoder: NSCoder) {

           let itemName = aDecoder.decodeObject(forKey: "Item.name") as! String        
           self.init(itemName: itemName)

           embeddedSpell = aDecoder.decodeObject(forKey: "Item.embeddedSpell") as? KnockbackComponent
           if embeddedSpell != nil {
              addComponent(self.embeddedSpell!)
           }
       }

      //Other codes
 }

Other class

class KnockbackComponent: GKComponent {
        weak var item: ItemEntity!
        
        init(anItem: ItemEntity) {
            item = anItem
            super.init()
        }
        
        override func encode(with aCoder: NSCoder) {
        
            aCoder.encode(item, forKey: "KnockbackComponent.item")
            super.encode(with: aCoder)
        }
        
        required convenience init?(coder aDecoder: NSCoder) {
            //***This line causes crash with error msg Thread 1: EXC_BAD_INSTRUCTION***//
            let item = aDecoder.decodeObject(forKey: "KnockbackComponent.item") as? ItemEntity //<--error msg Thread 1: EXC_BAD_INSTRUCTION
            self.init(anItem: item!)
        }
        
        
        //Other codes
        
  }
Bob
  • 155
  • 1
  • 8
  • Set the Exception Breakpoint. It gives you more information about the crash. – vadian Aug 12 '21 at 05:16
  • I did try setting breakpoints but didn't learn anything useful. Once it hits that breakpoint the app crashes and can't continue. – Bob Aug 12 '21 at 06:09
  • GKEntity isn't encodable according to the docs (it isn't listed as a conforming type) and this answer [here](https://developer.apple.com/forums/thread/33214) also mentions this. Whether [this](https://maartene.github.io/blog/files/65809d1ba21f44a8d31d35dd38a9c6cd-17.html) blog post covering the issue helps you or not I'm not sure. – JohnL Aug 12 '21 at 08:29
  • That can't be right as I have no trouble encoding/decoding GKEntity objects. As a matter of fact I can encode/decode other types of GKComponents (i.e. animation component, spritecomponent, etc.) as well. Only got stuck on this particular component. That's why it baffles me. – Bob Aug 12 '21 at 14:41
  • I checked out the blog link you provided and it's proven to be most useful. I ended up getting my GKComponent class to conform to Codable and everything worked out! Thank you so much! – Bob Aug 13 '21 at 02:58
  • Great stuff, good to hear you have resolved the issue. – JohnL Aug 14 '21 at 01:08

1 Answers1

0

I've resolved the issue by getting my GKComponent class to conform to Codable with the codes below:

override func encode(to encoder: Encoder)  {
        
    var container = encoder.container(keyedBy: CodingKeys.self)
    try? (container.encode(itemEnt, forKey: .itemEnt))
         
}
    
    
required convenience init(from decoder: Decoder) throws {
        
    let container = try decoder.container(keyedBy: CodingKeys.self)
       
    let itemEntity = try container.decode(ItemEntity.self, forKey: .itemEnt)
        self.init(entity: itemEntity)
}
Bob
  • 155
  • 1
  • 8