-1

Let me preface that my code has been obscured a little on purpose. I know the name won't be good. I am trying to add a widget to my app with the new iOS 8 functionality. I am using this link as a tutorial

Now, so far I have this in my ViewController when my submit button is called in my app. By this time I have all my data in that array to be passed on.

//Passes the array of times to the shared group to be called by the notification center widget.
NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.myGroup.TodayExtensionSharingDefaults"];
NSData *encodedArray = [NSKeyedArchiver archivedDataWithRootObject:tableViewController.TimeArray];
[sharedDefaults setObject:encodedArray  forKey:@"TimesArray"];
[sharedDefaults synchronize];

However, my array stores a custom data model I created, so in my data model I have:

- (void)encodeWithCoder:(NSCoder *)encoder {
    //Encode properties, other class variables, etc
    [encoder encodeInt:_stopNumber forKey:@"stopNumber"];
    [encoder encodeObject:_route forKey:@"route"];
    [encoder encodeObject:_number forKey:@"number"];
    [encoder encodeInt:_time forKey:@"time"];
    [encoder encodeObject:_minutesOrApproaching forKey:@"@minutesOrApproaching"];
    [encoder encodeObject:_noPrediction forKey:@"noPrediction"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if(self) {
        //decode properties, other class vars
        _stopNumber = [decoder decodeIntForKey:@"stopNumber"];
        _route = [decoder decodeObjectForKey:@"route"];
        _number = [decoder decodeObjectForKey:@"number"];
        _time = [decoder decodeIntForKey:@"time"];
        _minutesOrApproaching = [decoder decodeObjectForKey:@"minutesOrApproaching"];
        _noPrediction = [decoder decodeObjectForKey:@"noPrediction"];
    }
    return self;
}

And then in my Widget I have this code being called:

NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.myGroup.TodayExtensionSharingDefaults"];
    NSData *myDecodedObject = [defaults objectForKey: @"TimesArray"];
    NSArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: myDecodedObject];

    int i = 0;
    for (ETA *eta in decodedArray) {
        if(i == 0){
            _stopNumber.text = eta.number;
        }
        UILabel *label = [timeSlots objectAtIndex:i];
        label.text = eta.minutesOrApproaching;
        i++;
    }

My issue is that I keep getting:

* Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '* -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (ETA)' enter code here

So I am a little off put because I don't know what I am doing wrong here. It would be really great if someone could help point me in the right direction. Thanks again!

David
  • 402
  • 2
  • 9
  • 22
  • 1
    You probably shouldn't be using `NSUserDefaults` to store app data. Perhaps use a database or a custom data file format. – Droppy Sep 25 '14 at 13:51
  • This isn't about storing a mutable array, it's about [storing a custom object in NSUserDefaults](http://stackoverflow.com/questions/2315948/how-to-store-custom-objects-in-nsuserdefaults?rq=1) (or, in this case, an array of custom objects), isn't it? – DarkDust Sep 25 '14 at 13:53
  • Yes, but I wasn't sure if it had to do with the mutable array or not. Also, I am using the AppData option in the capabilities section of my app as per the tutorial. – David Sep 25 '14 at 13:56
  • 2
    No, the mutable array will simply be treated as a normal `NSArray`. I can't spot anything obvious, your code looks fine to me. While searching for this message I've seen two common problems: missing symbols (forgot to add a framework) or some rare linking problems. So try cleaning and building from scratch (and deleting your app from the device) and make sure your widget really does include (link) your class. – DarkDust Sep 25 '14 at 14:01
  • @David `_time` is an int ?? – meda Sep 25 '14 at 14:56
  • @David have you tested my answer below – meda Sep 25 '14 at 15:19
  • 1
    @meda Yes I am implementing it now. I am not getting an error anymore, which is good, but my labels don't seem to be changing, so I have to figure out what's going on. – David Sep 25 '14 at 15:24
  • You are creating the label but did not add it anywhere, basically each time you iterate you are creating a new instance but never added it to the view, try loging `eta.minutesOrApproaching` like `NSLog(@"minutesOrApproaching =%@", eta.minutesOrApproaching);` – meda Sep 25 '14 at 15:27
  • Yeh I was going to do that, but it seems like the method isn't even being called. I placed breakpoints, but the debugger isn't even stopping there, which leads me to believe it isn't being called. – David Sep 25 '14 at 15:31

1 Answers1

1

So, turns out passing custom classes can be a pain. And although all the code seems to be right, I am still getting the error. So I stepped back and looked at my custom object and asked myself "What is it that I really need from this?" and using that process decided I only needed certain values, so with that I encrypted only those values and not the object. Since those values were ints and strings, they are built into iOS on how to encode and decode. From there, I was able to pass the values around thanks to @meda's answer and my idea.

David
  • 402
  • 2
  • 9
  • 22
  • There is a huge difference between "encrypted" and "encoded", perhaps you mean "encoded". – zaph Sep 25 '14 at 18:02