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"]; }
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; }
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