当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《在NSUserDefaults中的NSMutableArray中存储自定义对象》经验,为你挑选了2个好方法。

我最近一直试图将我的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];
}

它对我来说很完美.

带着敬意,

斯特凡



1> Brad Larson..:

为了在数组中加载自定义对象,这就是我用来获取数组的方法:

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发生.
您不应该将数组存储到nsuserdefaults中,因为数组对于nsuserdefaults来说可能会变得太大.应该使用+(BOOL)archiveRootObject:(id)rootObject toFile:(NSString*)路径将其存储到文件中.为什么这个答案投票如此之多?
@Goodsum - 不,这很好用.试试吧,它会返回一个确实可变的NSMutableArray.它只是通过向其添加项目数组来启动新数组.

2> 小智..:

我认为你的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];
}

它对我来说很完美.

带着敬意,

斯特凡


斯蒂芬你是生命保护者,看看这里; 那行保存了我的想法"if(self = [super init])"http://stackoverflow.com/questions/1933285/nskeyedunarchiver-memory-leak-problem/1933399#1933399
推荐阅读
凹凸曼00威威_694
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有