将自定义对象存储在NSUserDefaults中的NSMutableArray中
我最近一直试图将我的iPhone应用程序的search结果存储在NSUserDefaults集合中。 我也使用这个来保存用户注册信息,但由于某种原因,试图存储自定义位置类的NSMutableArray总是回到空。
我试图将NSMutableArray转换为NSData元素作为这篇文章,但我得到了相同的结果( 可能保存一个整数数组在iPhone上使用NSUserDefaults? )
我试过的代码示例是:
保存:
[prefs setObject:results forKey:@"lastResults"]; [prefs synchronize];
要么
NSData *data = [NSData dataWithBytes:&results length:sizeof(results)]; [prefs setObject:data forKey:@"lastResults"];
要么
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results]; [prefs setObject:data forKey:@"lastResults"];
加载:
lastResults = (NSMutableArray *)[prefs objectForKey:@"lastResults"];
要么
NSData *data = [prefs objectForKey:@"lastResults"]; memcpy(&lastResults, data.bytes, data.length);
要么
NSData *data = [prefs objectForKey:@"lastResults"]; lastResults = [NSKeyedUnarchiver unarchiveObjectWithData:data];
在下面的build议下面我也已经在我的对象中实现了NSCoder(忽略NSString临时过度使用):
#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"]; }
为了在数组中加载自定义对象,这是我用来抓取数组的:
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]; }
您应该检查从用户默认返回的数据不是零,因为我相信从nil unarchive导致崩溃。
归档很简单,使用下面的代码:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"savedArray"];
正如f3lix指出的那样,您需要使自定义对象符合NSCoding协议。 添加类似下面的方法应该可以做到这一点:
- (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; }
我认为你的initWithCoder方法中有一个错误,至less在你提供的代码中你没有返回“self”对象。
- (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"]; } return self; // this is missing in the example above }
我用
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results]; [prefs setObject:data forKey:@"lastResults"];
和
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults]; NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"lastResults"]; if (dataRepresentingSavedArray != nil) { NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray]; if (oldSavedArray != nil) objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray]; else objectArray = [[NSMutableArray alloc] init]; }
它对我来说是完美的。
带着敬意,
斯特凡
我认为它看起来像你的代码的问题是不保存结果数组。 它的加载数据尝试使用
lastResults = [prefs arrayForKey:@"lastResults"];
这将返回由该键指定的数组。
请参阅“为什么NSUserDefaults无法在iPhone SDK中保存NSMutableDictionary?”( 为什么NSUserDefaults无法在iPhone SDK中保存NSMutableDictionary? )
如果你想(去)序列化自定义对象,你必须提供函数来(去)序列化数据(NSCoding协议)。 您引用的解决scheme适用于int数组,因为数组不是对象,而是连续的内存块。
我会build议不要试图在默认的数据库中存储这样的东西。
SQLite是相当容易拿起和使用。 我在我的屏幕录像( http://pragprog.com/screencasts/v-bdiphone )中有一段关于我写的一个简单的包装(你可以在不购买SC的情况下获得代码)。
在应用程序空间中存储应用程序数据要干净得多。
所有这一切说,如果它仍然是有道理的,把这个数据放入默认的数据库,然后看postf3lix张贴。