8

I've got a user object that I need to store in NSUserDefaults and share with an iOS 8 extension app (Watchkit). In the main container app, I can encode and decode the object without any problem. However, when I try to retrieve the stored user object in the Extension, I get a "'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class" error.

As far as I can see NSCoding has been implemented correctly in the object (and I'm able to encode and decode the object in the 'main' app).

Code in 'Container' app to store user object.

//Store user data in NSUserDefaults
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.mygroup"];

SFUserAccount *user = [SFUserAccountManager sharedInstance].currentUser;

NSData *userEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:user];
[defaults removeObjectForKey:@"SF User Acct1"]; //remove any old values
[defaults setObject:userEncodedObject forKey:@"SF User Acct1"];

[defaults synchronize];
SFUserAccount *decodedUser =  [NSKeyedUnarchiver unarchiveObjectWithData:userEncodedObject];

The last line above to perform a test decode in the main app works fine.

The code to retrieve from NSUserDefaults and decode in the extension target is below.

NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.mygroup"];
    NSData *archivedUser = [defaults objectForKey:@"SF User Acct1"];



    if (archivedUser){
        SFUserAccount *user =  [NSKeyedUnarchiver unarchiveObjectWithData:archivedUser];
    }

In the extension code, I get a "'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class"

Any suggestions as to where I should start looking? The app compiles fine which leads me to believe that the required frameworks have been included in the Extension target.

Duncan Babbage
  • 19,972
  • 4
  • 56
  • 93
YogiBotics
  • 81
  • 2
  • 1
    Is the implementation file where SFUserAccount is defined is added in extension's target? – msk Nov 30 '14 at 20:02
  • 1
    The binary is included in target. But your question led me to research a bit further. It turns out that I had to set the Set Other Linker Flags to "-ObjC -all_load". I'm not sure exactly what it does, but it work now!! Many thanks for your help. – YogiBotics Nov 30 '14 at 23:18
  • those linking flags are probably a bit overkill. Check if the class files belong to both targets instead. – dwery Dec 21 '14 at 13:17
  • @YogiBotics I'm having this same issue with NSKeyedUnarchiver, but the class I'm trying to decode does belong to both targets and I have tried adding the Other Linker Flags, but no luck. Any ideas? Or should I open a new question? – mdewitt Jan 25 '15 at 19:14

1 Answers1

9

For your WatchKit Extension to be able to decode SFUserAccount objects, it needs to understand the SFUserAccount class. To enable this, it should be added to your WatchKit Extension.

  1. Click on your project name in the Project Navigator, at the top of the left column in Xcode. (Press Cmd-1 to show the Project Navigator if it is hidden.
  2. Click to highlight the name of your WatchKit Extension on the left of the main window, under 'Targets'. (NOTE: highlight your WatchKit Extension, not the WatchKit App.
  3. Select 'Build Phases' in the items across the top.
  4. Next to 'Compile Sources', use the disclosure triangle to view the section if it is not already visible.
  5. Click the '+' at the bottom of the section to add a new source.
  6. From the list, select the .m file for the Class you need to add (in this case, the SFUserAccount.m file).
  7. Click 'Add'.
  8. Build and run.
Duncan Babbage
  • 19,972
  • 4
  • 56
  • 93
  • Nice! I needed this when I tried to pass a user defined class between iOS host app and the WatchKit extension. – Shu Suzuki Mar 20 '15 at 19:04