I am trying to send a "Class" to my Watchkit extension but I get this error.
* Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '* -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (MyApp.Person)
Archiving and unarchiving works fine on the iOS App but not while communicating with the watchkit extension. What's wrong?
InterfaceController.swift
    let userInfo = ["method":"getData"]      WKInterfaceController.openParentApplication(userInfo,         reply: { (userInfo:[NSObject : AnyObject]!, error: NSError!) -> Void in              println(userInfo["data"]) // prints <62706c69 7374303...              if let data = userInfo["data"] as? NSData {                 if let person = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? Person {                     println(person.name)                 }             }      })   AppDelegate.swift
func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!,     reply: (([NSObject : AnyObject]!) -> Void)!) {          var bob = Person()         bob.name = "Bob"         bob.age = 25          reply(["data" : NSKeyedArchiver.archivedDataWithRootObject(bob)])         return }   Person.swift
class Person : NSObject, NSCoding {     var name: String!     var age: Int!      // MARK: NSCoding      required convenience init(coder decoder: NSCoder) {         self.init()         self.name = decoder.decodeObjectForKey("name") as! String?         self.age = decoder.decodeIntegerForKey("age")     }      func encodeWithCoder(coder: NSCoder) {         coder.encodeObject(self.name, forKey: "name")         coder.encodeInt(Int32(self.age), forKey: "age")     } } 
                According to Interacting with Objective-C APIs:
When you use the
@objc(name)attribute on a Swift class, the class is made available in Objective-C without any namespacing. As a result, this attribute can also be useful when you migrate an archivable Objective-C class to Swift. Because archived objects store the name of their class in the archive, you should use the@objc(name)attribute to specify the same name as your Objective-C class so that older archives can be unarchived by your new Swift class.
By adding the annotation @objc(name), namespacing is ignored even if we are just working with Swift. Let's demonstrate. Imagine target A defines three classes:
@objc(Adam) class Adam:NSObject { }  @objc class Bob:NSObject { }  class Carol:NSObject { }   If target B calls these classes:
print("\(Adam().classForCoder)") print("\(Bob().classForCoder)") print("\(Carol().classForCoder)")   The output will be:
Adam B.Bob B.Carol   However if target A calls these classes the result will be:
Adam A.Bob A.Carol   To resolve your issue, just add the @objc(name) directive:
@objc(Person) class Person : NSObject, NSCoding {     var name: String!     var age: Int!      // MARK: NSCoding      required convenience init(coder decoder: NSCoder) {         self.init()         self.name = decoder.decodeObjectForKey("name") as! String?         self.age = decoder.decodeIntegerForKey("age")     }      func encodeWithCoder(coder: NSCoder) {         coder.encodeObject(self.name, forKey: "name")         coder.encodeInt(Int32(self.age), forKey: "age")     } } 
                        I had to add the following lines after setting up the framework to make the NSKeyedUnarchiver work properly.
Before unarchiving:
NSKeyedUnarchiver.setClass(YourClassName.self, forClassName: "YourClassName")   Before archiving:
NSKeyedArchiver.setClassName("YourClassName", forClass: YourClassName.self) 
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With