在 NSUserDefaults 中存储 NSArray 时应用程序崩溃

Posted

技术标签:

【中文标题】在 NSUserDefaults 中存储 NSArray 时应用程序崩溃【英文标题】:App crashes when storing NSArray in NSUserDefaults 【发布时间】:2014-09-02 06:42:29 【问题描述】:

我无法在NsUserDefaults 中存储 NSArray。应用程序崩溃 在这一行 [savedData setObject:jsonValue forKey:@"JSONDATA"];

下面是我的代码。我在下面提到了我的日志错误

NSArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults];
[savedData setObject:jsonValue forKey:@"JSONDATA"];
[savedData synchronize];

错误日志:

*** Terminating app due to uncaught exception '`NSInvalidArgumentException`', reason: '*** -

[NSUserDefaults setObject:forKey:]: attempt to insert non-property list object <CFBasicHash 0x8c62b10 [0x1d2aec8]>type = immutable dict, count = 3,
    entries =>

【问题讨论】:

你能检查一下jsonValue的内容吗? 我想这就是你要找的东西:***.com/questions/19720611/… 请 NSLog 您尝试存储的值。我们所拥有的只是一条错误消息,在事情变得有趣之前很久就被切断了。 【参考方案1】:

是的,它们不能像这样保存在 NSUserDefaults 中。

我正在下面写一个代码,请看一下,更多研究去看看苹果文档好吗。

代码在这里:

//用于保存

NSData *dataSave = [NSKeyedArchiver archivedDataWithRootObject:yourArrayToBeSave]];
[[NSUserDefaults standardUserDefaults] setObject:dataSave forKey:@"array"];

[[NSUserDefaults standardUserDefaults] synchronize]; // this will save you UserDefaults

//用于检索

NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"array"];
NSArray *savedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];

【讨论】:

为什么将 NSData 转换为 NSArray 并返回 NSData? 是的,我正在使用它,但应用程序崩溃了。【参考方案2】:

虽然 kshitij 的回答是正确的,但遗憾的是,它并没有就此结束。如果您想将自定义对象保存在您的NSUserDefaults 中,您的自定义对象必须实现NSCoding 协议并覆盖initWithCoderencodeWithCoder 方法。这样的例子可以是:

@interface Book : NSObject <NSCoding>
@property NSString *title;
@property NSString *author;
@property NSUInteger pageCount;
@property NSSet *categories;
@property (getter = isAvailable) BOOL available;
@end

@implementation Book

#pragma mark - NSCoding

    - (id)initWithCoder:(NSCoder *)decoder 
        self = [super init];
        if (!self) 
            return nil;
        

        self.title = [decoder decodeObjectForKey:@"title"];
        self.author = [decoder decodeObjectForKey:@"author"];
        self.pageCount = [decoder decodeIntegerForKey:@"pageCount"];
        self.categories = [decoder decodeObjectForKey:@"categories"];
        self.available = [decoder decodeBoolForKey:@"available"];

        return self;
    

    - (void)encodeWithCoder:(NSCoder *)encoder 
        [encoder encodeObject:self.title forKey:@"title"];
        [encoder encodeObject:self.author forKey:@"author"];
        [encoder encodeInteger:self.pageCount forKey:@"pageCount"];
        [encoder encodeObject:self.categories forKey:@"categories"];
        [encoder encodeBool:[self isAvailable] forKey:@"available"];
    

@end

【讨论】:

【参考方案3】:

这样试试

 NSMutableArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSData *yourEncodedObject = [NSKeyedArchiver archivedDataWithRootObject: jsonValue];

       NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults];
        [userData setObject: yourEncodedObject forKey:@"JSONDATA"];
    [savedData synchronize];

【讨论】:

你能告诉你json数据吗,NSArray *jsonValue里面是什么?【参考方案4】:

我认为 jsonValue 是 NSDictionary 而不是 NSArray..

 id jsonValue = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
    if ([jsonValue isKindOfClass:[NSDictionary class]])
    
   NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue];
   [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"];
    [savedData synchronize];
    

//(或)

NSDictionary *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"];
[savedData synchronize];

另外我认为你不能将 NSDictionary 直接存储到 NSUserDefaults 中。通过@kshitij godara 完成/保存。

您可以使用 NSKeyedArchiver 将您的字典写入 NSData。

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"];

检索数据:

NSData *dictionaryData = [defaults objectForKey:@"JSONDATA"];
NSDictionary *dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:dictionaryData];

希望这对您有所帮助..!

【讨论】:

你从 NSData 开始。您将 NSData 转换为字典或数组。您将字典或数组转换为 NSData 并存储它。你能在你的代码中看到这两个完全没有意义的步骤吗?【参考方案5】:

NSUserDefaults 接受属性列表对象 - NSDictionary、NSArray、NSString、NSNumber、NSDate 和 NSData。 JSON 文档包含 NSDictionary、NSArray、NSString、NSNumber 和 NSNull。您会看到区别 - 属性列表对象不能包含 NSNull 值。

如果您的 JSON 对象包含一个 NSNull 对象(您解析的 JSON 文档包含一个“null”值),那么您不能将它存储到 NSUserDefaults 中。除此之外,所有说你不能在 NSUserDefaults 中存储 JSON 数据的 cmets 都是无稽之谈。只有 NSNull 对象会导致问题。

您的问题有一个非常非常简单的解决方案。只需将原始 json 数据作为 NSData 对象存储在 NSUserDefaults 中。然后,当您阅读 NSUserDefaults 时,您会获得 NSData 并解析它们。而不是

NSArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults];
[savedData setObject:jsonValue forKey:@"JSONDATA"];
[savedData synchronize];

你随便写

NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults];
[savedData setObject:data forKey:@"JSONDATA"];
[savedData synchronize];

【讨论】:

显然是最佳答案。【参考方案6】:

NSUserDefaults 最多只能用于 500k 的数据 (https://forums.developer.apple.com/message/50696#50696)

如果存储大量应用程序可能会崩溃,从个人经验来看,我已经看到存储 1MB 数据的应用程序在 [NSUserDefaults setObject:] 和 [NSUserDefaults 同步] 时/之后不久崩溃;

要检查实时应用程序使用了多少数据,请打开 Xcode -> 窗口 -> 设备,选择您的设备,在已安装的应用程序中选择您的应用程序并下载应用程序容器。默认值存储在 AppData->Preferences->your.app.plist

将数据保存到用户默认值的另一种方法是写入文件:

-(void)saveObject:(NSObject *)object toFile:(NSString *)name 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:name];
    [NSKeyedArchiver archiveRootObject:object toFile:appFile];


-(NSObject *)loadFromFile:(NSString *)name 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:name];

    if([[NSFileManager defaultManager] fileExistsAtPath:appFile])
        return [NSKeyedUnarchiver unarchiveObjectWithFile:appFile];
    else
        NSLog(@"No File: %@", name) ;
        return nil ;
    


【讨论】:

以上是关于在 NSUserDefaults 中存储 NSArray 时应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

NSUserDefaults 简介,使用 NSUserDefaults 存储自定义对象

将数据存储到 NSUserDefaults

如何使用 NSUserDefaults 在 Swift 中存储自定义类数组?

将 NSobject 数据存储到 Nsuserdefaults

NSUserDefaults 简介

如何在通过共享扩展选择的 NSUserDefaults 中存储多个图像