美文网首页iOS开发常用iOS
NSUserDefaults 存储可变数组问题

NSUserDefaults 存储可变数组问题

作者: dvlproad | 来源:发表于2017-07-14 20:30 被阅读2719次

前言

NSUserDefaults支持的数据类型有:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL.

附:NSUserDefaults 虽然本身不支持自定义对象的存储,不过它支持NSData的类型。所以当我们要在NSUserDefaults中存储的是自定义的对象的时候,需要将该自定义对象转成NSData存储。而自定义对象转data的方式我们通过<NSCoding>来实现。这里提前讲到,下面会详细介绍。

1、NSUserDefaults 存储数组问题

①如果数组中的对象不是自定义的对象,那么可直接存储。如:

    NSArray *array = @[@"1", @"2", @"3", @"4"];
    [[NSUserDefaults standardUserDefaults] setObject:array forKey:@"key"];
    
    [[NSUserDefaults standardUserDefaults] synchronize];

②如果数组中的对象是自定义的对象,那么需要先让这个自定义类实现<NSCoding>协议中的- (id) initWithCoder: (NSCoder *)coder方法和- (void) encodeWithCoder: (NSCoder *)coder方法,然后把该自定义的类对象编码到NSData中,再从NSUserDefaults中进行读取。

//User.h
@interface User : NSObject<NSCoding> //注意:这里需要实现NSCoding协议

@property (nonatomic, copy) NSString *realName;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, copy) NSString *password;

@end

//User.m
@implementation User

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        self.realName = [aDecoder decodeObjectForKey:@"realName"];
        self.nickName = [aDecoder decodeObjectForKey:@"nickName"];
        self.password = [aDecoder decodeObjectForKey:@"password"];
    }
    
    return self;
}


- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.realName forKey:@"realName"];
    [aCoder encodeObject:self.nickName forKey:@"nickName"];
    [aCoder encodeObject:self.password forKey:@"password"];
}

@end

这时,存储自定义对象的数组的获取与保存方法如下

    //存储
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    NSArray *array = @[customObject1, customObject2, customObject3, customObject4];
    NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:array];
    [userDefaults setObject:arrayData forKey:@"arrayKey"];
    [userDefaults synchronize];
    
    //取出
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    NSData *arrayData = [userDefaults  objectForKey:@"arrayKey"];
    NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:arrayData];
2、NSUserDefaults 存储自定义对象的问题见上
3、修改存储在NSUserDefaults中的数组

废话不多说上代码,项目中遇到的问题是:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *array = [userDefaults objectForKey:@"theArrayKey"]];

[array addObject:@"some new value"];
[userDefaults setObject: array forKey:@"theArrayKey"]; //会卡住主程序

[[NSUserDefaults standardUserDefaults] synchronize];

这句话取出了数组,可是当对数组添加元素后,进行存储时卡在了下面这句话:
[userDefaults setObject: array forKey:@"theArrayKey"];
时候会把主线程卡住,但是不崩溃,不知道为何,就Google了,stackoverflow给了解答办法,

When you store mutable objects to NSUserDefaults, it stores an immutable copy of it so you can't change it directly like that. You have to get the mutable copy out of defaults, change it, and then set it back, replacing old object in defaults.
即:修改存储在NSUserDefaults中的数组:我们从NSUserDefaults中取出的数组是不可变的(因为NSUserDefaults 存储的对象全是不可变的)。所以当我们需要修改存储在NSUserDefaults中的数组时,需要用一个新的可变数组来保存之前的值,再修改,之后再保存,即修改的过程应该如下:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *array = [userDefaults objectForKey:@"theArrayKey"]];

NSMutableArray *mutableCopyArray = [array mutableCopy]; //重要步骤操作mutableCopyArray
[mutableCopyArray addObject:@"some new value"];
[userDefaults setObject: mutableCopyArray forKey:@"theArrayKey"];

[[NSUserDefaults standardUserDefaults] synchronize];

总结:NSUserDefaults 存储的对象全是不可变的(这一点非常关键,弄错的话程序会出bug),即存进NSUserDefaults的对象会变成不可变的,同样取出来的对象肯定是不可变的。

其它

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

相关文章

  • oc中NSUserDefaults使用问题关于NSDiction

    NSUserDefaults中只可以存储不可变数据,如果存储一个可变的数组或可变字典,取出数据时数组或字典变成不可...

  • NSUserDefaults 存储可变数组问题

    前言 NSUserDefaults支持的数据类型有:NSNumber(NSInteger、float、double...

  • 2021-12-01 NSUserDefault 存入NSM

    当你使用NSUserDefaults存储可变对象,它存储的是一个不可变的副本,你无法像这样直接改变它。你必须把数组...

  • iOS开发笔记 NSUserDefaults 存储可变数组问题

    不多废话,我在项目里遇到了这么一个问题:把数据存到一个可变数组里,然后用NSUserDefaults 存到沙盒中;...

  • 开发遇到的坑

    1、使用NSUserDefaults存储数组(自定义元素)崩溃,NSUserDefaults支持的数据类型有NSS...

  • 《每天进步一点点》DAY5:Java集合

    数组和集合区别 数组长度是固定的,不可变,集合长度可变 数组可存储基本数据类型,也可存储引用数据类型,集合只能存储...

  • IOS(swift)-数据存储 · 用NSUserDefault

    1.用NSUserDefaults存储配置信息 注:本次使用NSUserDefaults存储信息是在不考虑安全问题...

  • JavaSE总结(5)集合

    一、数组和集合: 数组 数组长度固定 数组可以存储任意类型元素 集合 集合长度可变 集合只能存储引用类型元...

  • 集合

    集合与数组的区别? 数组是不可变长度;集合是可变长度的,可以存储不同类型的元素 数组可以存储基本数据类型,也可以存...

  • iOS 中NSArray

    //OC 的数组 可以存储不同类型的对象 ,OC 的数组只能存储对象 //不可变数组 NSArray *array...

网友评论

    本文标题:NSUserDefaults 存储可变数组问题

    本文链接:https://www.haomeiwen.com/subject/vuuohxtx.html