0

I am a little bit confused about how to decode an SKSpriteNode.

I have the following SKSpriteNode class:

class Person : SKSpriteNode
{
  var gender : Gender
  var age : Age
  var positionX : CGFloat!
  var positionY : CGFloat!
  let frontTexture : SKTexture
  let backTexture : SKTexture

  required convenience init?(coder aDecoder: NSCoder)
  {

    print("INITIALIZED WITH DECODER????")

    guard let myPerson = aDecoder.decodeObject(forKey: "person") as? Person
        else { return nil }

    self.init(coder: aDecoder)
  }

  func encodeWithCoder(coder: NSCoder)
  {
    coder.encode(self, forKey: "person")
  }


  init(gender: Gender, age: Age, positionX: CGFloat, positionY: CGFloat, sceneSize: CGSize)
  {
    self.gender = gender
    self.age = age

    self.backTexture = SKTexture(imageNamed: "person_back")
    self.frontTexture = SKTexture(imageNamed: "person_front")

    var currentTexture = self.frontTexture

    super.init(texture: currentTexture, color: .clear, size: frontTexture.size())

    // Position of the person in the scene
    self.position = updatePosition(positionX: positionX, positionY: positionY, sceneSize: sceneSize)

  }

In a MultipeerConnection subclass, I use this to send encoded data (data seems to be archived correctly):

func sendData(dictionaryWithData dictionary: Dictionary<String, Any>, toPeer targetPeers: [MCPeerID])
  {
    let dataToSend = NSKeyedArchiver.archivedData(withRootObject: dictionary)

    do
    {
        try session.send(dataToSend, toPeers: targetPeers, with: MCSessionSendDataMode.reliable)
    }
    catch
    {
        print("ERROR")
    }
  }

with data made as follows (crowd is an array [Person]):

func makeMessageCrowd() -> Dictionary<String, Any>
  {

    var messageToSend = Dictionary<String, Any>()
    messageToSend["move"] = "start"
    messageToSend["action"] = appDelegate.persons
    return messageToSend
  }

I use the following to receive the data:

func session(_ session: MCSession,
             didReceive data: Data,
             fromPeer peerID: MCPeerID)
  {

    let message = NSKeyedUnarchiver.unarchiveObject(with: data) as! Dictionary<String, Any>

    if let moveType = message["move"] as? String
    {
        switch(moveType)
        {
        case "start":
            appDelegate.persons = message["action"] as! [Person]

        default:
            print("default")
        }
    }
  }

Right now, it starts initializing object Person with the convenience initializer, and then crashes here:

let message = NSKeyedUnarchiver.unarchiveObject(with: data) as! Dictionary<String, Any>

saying that it found a nil value. However, data seems to have 15000 bytes, so it was passed well.

If instead of a convenience initializer, I use this:

required init?(coder aDecoder: NSCoder)
  {
    //fatalError("NSCoding not supported")
    self.gender = Gender.male
    self.age = Age.young
    self.frontTexture = SKTexture(imageNamed: "person_front")
    self.backTexture = SKTexture(imageNamed: "person_back")
    self.positionX = 0
    self.positionY = 0

    super.init(coder: aDecoder)
  }

I do not have a crash, however the array [Person] on the peer device is created using the default values initialized as above, and not as passed.

This is the culprit since it returns nil:

guard let myPerson = aDecoder.decodeObject(forKey: "person") as? Person
        else { return nil }

How do I do encode and decode a custom class properly?

Thanks a lot!

Igor Tupitsyn
  • 1,193
  • 3
  • 18
  • 45

0 Answers0