【问题标题】:NSUserDefaults save two arrays leading to crashNSUserDefaults 保存两个数组导致崩溃
【发布时间】:2015-05-19 08:40:19
【问题描述】:

最近在学习NSUserDefaults,然后做了一个demo如下:

 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
 NSMutableArray *activity_array = [NSMutableArray array];
 NSMutableArray *movie_array = [NSMutableArray array];
 [defaults setObject:activity_array forKey:@"activity"];
 [defaults setObject:movie_array forKey:@"movie"];
 [defaults synchronize];

然后我尝试编写以下内容,在本文期间我将其称为“code2”:

 NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
 NSMutableArray *array = [userDefault objectForKey:@"activity"];
 [array addObject:@"123"];

演示仍然有效。
但是,当我将“code2”替换为以下代码时,演示会崩溃:

 NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
 NSMutableArray *array = [userDefault objectForKey:@"movie"];
 [array addObject:@"123"];

如您所见,差异是关键。
为什么会崩溃?

【问题讨论】:

  • 因为你的问题很简单,所以没有问你,但是当你说你有崩溃时,请确保添加崩溃日志/堆栈跟踪。如果你这样做了,你自己就可以得到答案,通过阅读日志,你可以看到:*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object' 非常清楚意味着你正在改变一个不可变对象。 ;-)
  • 先生,我想问更多,因为我想更改 NSUserDefault.so 存储的数组,所以我应该怎么做?
  • 如果您想修改数组的内容并再次保存,请按照我的回答(您刚刚接受的那个!)中的说明进行操作。第 1 步:从 userdefaults 中获取数组,第 2 步:制作数组的可变副本,第 3 步:添加/删除所需的对象,第 4 步,将数组保存在 userdefaults 中,现在已修改!
  • 我编辑了我的答案,使其更加清晰
  • 第4步,如何保存?只是[userDefaults synchronize]?我试过了,失败了。

标签: ios nsarray nsuserdefaults


【解决方案1】:

NSUserDefaults 可以存储NSMutableArrays,但会将它们变成不可变数组。

NSDictionaryNSMutableDictionary 也是如此。

这意味着如果您想将一个对象添加到刚刚从 NSUserDefaults 提取的数组中,您必须首先使其可变,例如使用 -mutableCopy-initWithArray

NSArray *array = [userDefault objectForKey:@"movie"];

//This works
NSMutableArray *arr = [NSMutableArray alloc]initWithArray:array];

//This works too and is more commonly used.
NSMutableArray *arr = [array mutableCopy];

您现在可以轻松修改数组arr,并且可以像以前一样保存它。如果您之后检索它,它将是修改后的数组。但请注意,arraysdictionariesNSUserDefaults 获取时始终是不可变的。每次您想从 NSUserDefaults 修改数组或字典时,您都必须执行该“技巧”。

编辑:在测试您的代码之后,我唯一的假设是当您检索它时,您的无崩溃数组只是零。使用断点进行调试以验证这一点,但我几乎 101% 确定。

EDIT2:木马比我更快!

【讨论】:

    【解决方案2】:

    正如其他人指出的那样,您从 NSUserDefaults 返回的数组是不可变的,因此在对它们调用 addObject: 时会抛出异常,但是如果数组是 nil 作为调用,则不会发生这种情况对nil 对象的方法(发送消息)会被静默忽略。

    因此,我相信您的 code2 作为对象 @"activity" 在用户默认值中不存在,而 @"movie" 存在。

    【讨论】:

      【解决方案3】:

      从 NSUserDefaults 返回的数组和字典总是不可变的,即使你设置的那个是可变的。您必须调用 -mutableCopy。

      【讨论】:

      • 您是否仔细检查过它是否返回了一个非零对象?
      【解决方案4】:

      试试这个:

      NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
      NSMutableArray *array = [[userDefault objectForKey:@"movie"]mutableCopy];
      

      【讨论】:

        【解决方案5】:

        来自 userDefault 的对象是不可变的。试试这个

        NSMutableArray *arr = (NSMutableArray *)[userDefault objectForKey:@"activity"];
        

        或者如果您喜欢使用 id 并首先检查其类以防止崩溃:

        id variableName = [userDefault objectForKey:@"activity"];
        
        if ([[variableName class] isEqual:[NSArray class]])
        {
             NSMutableArray *arr = [[NSMutableArray alloc] initWithArray:(NSArray *)variableName];
             NSMutableArray *arr = [(NSArray *)variableName mutableCopy];
        }
        else if ([[variableName class] isEqual:[NSNull class]])
            NSLog(@"no object with key:activity");
        else
            NSLog(@"not array");
        
        //Happy coding.. :)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-07
          • 1970-01-01
          • 2020-04-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-23
          • 2014-11-22
          相关资源
          最近更新 更多