在NSUserDefaults中将自定义对象存储在NSMutableArray中

问题描述:

我最近一直试图将我的iPhone应用程序的搜索结果存储在NSUserDefaults集合中。我也使用它来成功保存用户注册信息,但由于某种原因,试图存储自定义位置类的NSMutableArray始终为空。在NSUserDefaults中将自定义对象存储在NSMutableArray中

我试图转换的NSMutableArray到NSData的元素作为这个帖子的,但我得到了相同的结果(Possible to save an integer array using NSUserDefaults on iPhone?

我已经尝试了代码示例:

节省:

[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]; 

经过以下建议下面我也implemente d 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]; 
} 

您应该检查从用户默认返回的数据不为零,因为我相信解除封存从零导致崩溃。

存档很简单,使用下面的代码:

[[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; 
} 
+0

我已经将你的代码和实现NSCoder的对象复制到原型中,但是desp ite来自UserDefaults的NSData有数据,最终数组仍然有0的计数。任何想法?我会尝试将我的原型上传到某处 – 2009-02-13 16:31:50

请参阅“NSUserDefaults的为什么没能挽救的NSMutableDictionary在iPhone SDK? “(Why NSUserDefaults failed to save NSMutableDictionary in iPhone SDK?


如果你想(反)序列化的自定义对象,你必须提供的功能(反)序列化的数据(NSCoding协议)。该解决方案你是指与INT作品数组,因为数组是不是对象,而是一个连续的内存块。

+0

我认为您的权利,我会看看到NSCoding(除非你有一个建议linky),本身是由上NSString的对象是所有的,所以我想我可以写我自己的串行器,并把它们全部放入一个字符串数组 – 2009-02-11 14:56:07

+0

好吧,所以我已经实现了NSCode,但仍然没有使用NSArchiver – 2009-02-11 16:29:53

我认为它看起来像你的代码不保存结果阵列的问题。它的加载数据尝试使用

lastResults = [prefs arrayForKey:@"lastResults"]; 

这将返回数组s通过钥匙特化。

我会建议不要试图在默认数据库中存储这样的东西。

SQLite很容易拾取和使用。我在我的一个屏幕录像(http://pragprog.com/screencasts/v-bdiphone)中插入了一段关于我写的简单包装(您可以在不购买SC的情况下获得代码)。

在应用程序空间中存储应用程序数据要干净得多。

所有这一切说,如果它仍然是有道理的把这个数据放入默认的数据库,然后看到帖子f3lix张贴。

+1

谢谢你的建议,但我真的不想开始编写SQL查询我在你的例子中看到)只是为了一个有几个字符串的对象 – 2009-02-11 16:58:39

我想你已经在你的initWithCoder方法得到一个错误,至少在所提供的代码,你不回的“自我”的对象。

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

和它的工作非常适合我。

与问候,

斯特凡