我最近一直试图将我的iPhone应用程序的搜索结果存储在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];
按照下面的建议后,我也在我的对象中实现了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"]; }
Brad Larson.. 177
为了在数组中加载自定义对象,这就是我用来获取数组的方法:
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,因为我相信从nil取消归档会导致崩溃.
使用以下代码存档很简单:
[[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:方法结束时错过了"返回自我".添加它似乎允许unarchiving发生. (3认同)
您不应该将数组存储到nsuserdefaults中,因为数组对于nsuserdefaults来说可能会变得太大.应该使用+(BOOL)archiveRootObject:(id)rootObject toFile:(NSString*)路径将其存储到文件中.为什么这个答案投票如此之多? (2认同)
@Goodsum - 不,这很好用.试试吧,它会返回一个确实可变的NSMutableArray.它只是通过向其添加项目数组来启动新数组. (2认同)
小智.. 13
我认为你的initWithCoder方法中出现了错误,至少在提供的代码中你没有返回'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]; }
它对我来说很完美.
带着敬意,
斯特凡
为了在数组中加载自定义对象,这就是我用来获取数组的方法:
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,因为我相信从nil取消归档会导致崩溃.
使用以下代码存档很简单:
[[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方法中出现了错误,至少在提供的代码中你没有返回'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]; }
它对我来说很完美.
带着敬意,
斯特凡