Xcode 12.5 NSCoding issue with SpriteKit/GameplayKit

101 views Asked by At

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
        
  }
1

There are 1 answers

0
Bob On

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)
}