0

Am trying to transfer an array of custom objects from iOS to watchkitextension.

Understood that in order to do so, data needs to be encoded. Am though getting error when decoding.

Here we go:

The custom object:

    final class Person: NSObject {
        var PersonName:String = ""
        var PersonAge:Int = 0
        var joined:NSDate = NSDate()

        init(PersonName: String, PersonAge:Int, joined:NSDate){
            self.PersonName = PersonName
            self.PersonAge = PersonAge
            self.joined = joined
            super.init()
        }
    }

   extension Person: NSCoding {
        private struct CodingKeys {
            static let PersonName = "PersonName"
            static let PersonAge = "PersonAge"
            static let joined = "joined"
        }

        convenience init(coder aDecoder: NSCoder) {
            let PersonName = aDecoder.decodeObjectForKey(CodingKeys.PersonName) as! String
            let PersonAge = aDecoder.decodeIntForKey(CodingKeys.PersonAge) as! Int
            let joined = aDecoder.decodeDoubleForKey(CodingKeys.joined) as! NSDate

            self.init(PersonName: PersonName, PersonAge: PersonAge, joined: joined)
        }

        func encodeWithCoder(encoder: NSCoder) {
            encoder.encodeObject(PersonName, forKey: CodingKeys.PersonName)
            encoder.encodeObject(PersonAge, forKey: CodingKeys.PersonAge)
            encoder.encodeObject(joined, forKey: CodingKeys.joined)
        }
    }

The class with the array:

@objc(Group)
final class Group: NSObject {

    static let sharedInstance = Group()

    var Persons:[Person] = []

    required override init() {
        super.init()
    }

    init (Persons:[Person]){
        self.Persons = Persons
        super.init()
    }

}

extension Group: NSCoding {
    private struct CodingKeys {
        static let Persons = "Persons"
    }

    convenience init(coder aDecoder: NSCoder) {

        let Persons = aDecoder.decodeObjectForKey(CodingKeys.Persons) as! [Person]
        self.init(Persons: Persons)

        self.Persons = aDecoder.decodeObjectForKey(CodingKeys.Persons) as! [Person]
    }

    func encodeWithCoder(encoder: NSCoder) {
        encoder.encodeObject(Persons, forKey: CodingKeys.Persons)
    }
}

Creating example object, append to array, then encode:

let aPerson:Person? = Person(PersonName: "Martin", PersonAge: 50, joined: NSDate())

Group.sharedInstance.Persons.append(aPerson!) 
let encodedData = NSKeyedArchiver.archivedDataWithRootObject(Group.sharedInstance)

And here I get the error "execution was interrupted - reason signal SIGABRT"

let decodedData = NSKeyedUnarchiver.unarchiveObjectWithData(encodedData) as? Group
TPeter
  • 463
  • 3
  • 15

1 Answers1

0

Try changing these sections to:

convenience init(coder aDecoder: NSCoder) {
    let PersonName = aDecoder.decodeObjectForKey(CodingKeys.PersonName) as! String
    let PersonAge = aDecoder.decodeIntForKey(CodingKeys.PersonAge) as! Int
    let joined = aDecoder.decodeObjectForKey(CodingKeys.joined) as! NSDate

    self.init(PersonName: PersonName, PersonAge: PersonAge, joined: joined)
}

func encodeWithCoder(encoder: NSCoder) {
    encoder.encodeObject(PersonName, forKey: CodingKeys.PersonName)
    encoder.encodeInt(PersonAge, forKey: CodingKeys.PersonAge)
    encoder.encodeObject(joined, forKey: CodingKeys.joined)
}

So that the serialization matches the deserialization, and the types desired by the Person class. That said, the WWDC talk on WatchConnectivity specifically recommended not to use NSKeyedArchiver as it is not a very space efficient serialization method.

ccjensen
  • 4,578
  • 2
  • 23
  • 25
  • Thank your for highlighting this mismatch. Unfortunately still same issue. If not NSKeyedArchiver, what do you use? (I tried JSON parsing direct from watchkitextension, which works well on simulator but times out on physical device, therefore am reverting now to do parsing from phone and then pass the data on) – TPeter Oct 19 '15 at 22:30
  • NSPropertyListSerialization was one of the ones recommended by the WatchConnectivity engineers. Just make sure to only use property list types (which it looks like you are). Basically you would add a `-(NSDictionary *)dictRepresentation` and a `-(id)initWithDictionaryRepresentation:(NSDictionary *)dictionaryRepresentation` to your Person class. – ccjensen Oct 19 '15 at 22:32
  • If you are still hitting an issue you must have a bug somewhere else in your code. Since the process is crashing you should be getting crash reports generated which will tell you exactly where the problem is. – ccjensen Oct 19 '15 at 22:33
  • sorry ccjensen, I am still new to Swift. How / where do you do this with NSPropertySerialization? – TPeter Oct 24 '15 at 07:13