Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing custom objects in an NSMutableArray in NSUserDefaults

Tags:

cocoa-touch

I've recently been trying to store the search results of my iPhone app in the NSUserDefaults collection. I also use this to save user registration info successfully, but for some reason trying to store my NSMutableArray of custom Location classes always comes back empty.

I tried converting the NSMutableArray to a NSData element as of this post but I get the same result (Possible to save an integer array using NSUserDefaults on iPhone?)

The code samples I have tried are:

Save:

[prefs setObject:results forKey:@"lastResults"]; [prefs synchronize]; 

or

NSData *data = [NSData dataWithBytes:&results length:sizeof(results)]; [prefs setObject:data forKey:@"lastResults"]; 

or

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results]; [prefs setObject:data forKey:@"lastResults"]; 

Load:

lastResults = (NSMutableArray *)[prefs objectForKey:@"lastResults"]; 

or

NSData *data = [prefs objectForKey:@"lastResults"]; memcpy(&lastResults, data.bytes, data.length);   

or

NSData *data = [prefs objectForKey:@"lastResults"]; lastResults = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 

After following advice below I have also implemented NSCoder in my object (ignore the overuse of NSString its temporary):

#import "Location.h"   @implementation Location  @synthesize locationId; @synthesize companyName; @synthesize addressLine1; @synthesize addressLine2; @synthesize city; @synthesize postcode; @synthesize telephoneNumber; @synthesize description; @synthesize rating; @synthesize priceGuide; @synthesize latitude; @synthesize longitude; @synthesize userLatitude; @synthesize userLongitude; @synthesize searchType; @synthesize searchId; @synthesize distance; @synthesize applicationProviderId; @synthesize contentProviderId;  - (id) initWithCoder: (NSCoder *)coder {     if (self = [super init])     {         self.locationId = [coder decodeObjectForKey:@"locationId"];         self.companyName = [coder decodeObjectForKey:@"companyName"];         self.addressLine1 = [coder decodeObjectForKey:@"addressLine1"];         self.addressLine2 = [coder decodeObjectForKey:@"addressLine2"];         self.city = [coder decodeObjectForKey:@"city"];         self.postcode = [coder decodeObjectForKey:@"postcode"];         self.telephoneNumber = [coder decodeObjectForKey:@"telephoneNumber"];         self.description = [coder decodeObjectForKey:@"description"];         self.rating = [coder decodeObjectForKey:@"rating"];         self.priceGuide = [coder decodeObjectForKey:@"priceGuide"];         self.latitude = [coder decodeObjectForKey:@"latitude"];         self.longitude = [coder decodeObjectForKey:@"longitude"];         self.userLatitude = [coder decodeObjectForKey:@"userLatitude"];         self.userLongitude = [coder decodeObjectForKey:@"userLongitude"];         self.searchType = [coder decodeObjectForKey:@"searchType"];         self.searchId = [coder decodeObjectForKey:@"searchId"];         self.distance = [coder decodeObjectForKey:@"distance"];         self.applicationProviderId = [coder decodeObjectForKey:@"applicationProviderId"];         self.contentProviderId = [coder decodeObjectForKey:@"contentProviderId"];     } }  - (void) encodeWithCoder: (NSCoder *)coder {     [coder encodeObject:locationId forKey:@"locationId"];     [coder encodeObject:companyName forKey:@"companyName"];     [coder encodeObject:addressLine1 forKey:@"addressLine1"];     [coder encodeObject:addressLine2 forKey:@"addressLine2"];     [coder encodeObject:city forKey:@"city"];     [coder encodeObject:postcode forKey:@"postcode"];     [coder encodeObject:telephoneNumber forKey:@"telephoneNumber"];     [coder encodeObject:description forKey:@"description"];     [coder encodeObject:rating forKey:@"rating"];     [coder encodeObject:priceGuide forKey:@"priceGuide"];     [coder encodeObject:latitude forKey:@"latitude"];     [coder encodeObject:longitude forKey:@"longitude"];     [coder encodeObject:userLatitude forKey:@"userLatitude"];     [coder encodeObject:userLongitude forKey:@"userLongitude"];     [coder encodeObject:searchType forKey:@"searchType"];     [coder encodeObject:searchId forKey:@"searchId"];     [coder encodeObject:distance forKey:@"distance"];     [coder encodeObject:applicationProviderId forKey:@"applicationProviderId"];     [coder encodeObject:contentProviderId forKey:@"contentProviderId"];  } 
like image 851
Anthony Main Avatar asked Feb 11 '09 14:02

Anthony Main


1 Answers

For loading custom objects in an array, this is what I've used to grab the array:

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults]; NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"savedArray"]; if (dataRepresentingSavedArray != nil) {     NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];     if (oldSavedArray != nil)         objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];     else         objectArray = [[NSMutableArray alloc] init]; } 

You should check that the data returned from the user defaults is not nil, because I believe unarchiving from nil causes a crash.

Archiving is simple, using the following code:

[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"savedArray"]; 

As f3lix pointed out, you need to make your custom object comply to the NSCoding protocol. Adding methods like the following should do the trick:

- (void)encodeWithCoder:(NSCoder *)coder; {     [coder encodeObject:label forKey:@"label"];     [coder encodeInteger:numberID forKey:@"numberID"]; }  - (id)initWithCoder:(NSCoder *)coder; {     self = [super init];     if (self != nil)     {         label = [[coder decodeObjectForKey:@"label"] retain];         numberID = [[coder decodeIntegerForKey:@"numberID"] retain];     }        return self; } 
like image 121
Brad Larson Avatar answered Oct 22 '22 06:10

Brad Larson