iOS 8在更新UserDefaults对象时冻结



我有一个存储到NSUserDefaults的对象队列。当我需要向其中添加对象时,我调用以下方法:

+ (void)addCodeToQueue:(Code *)code {
  // Note: userDefaults is a static, initialized variable
  NSDictionary *codeModel = [self generateCodeModelWith:code];
  // Read array from UserDefaults, or create one if nil
  NSMutableArray *codeQueue = [userDefaults mutableArrayValueForKey:@"CodeQueue"] ? : [[NSMutableArray alloc] init];
  // Add code model
  [codeQueue addObject:codeModel];
  // Add/replace array & sync
  [userDefaults setObject:codeQueue forKey:@"CodeQueue"]; // App freezes here if uncommented
  [userDefaults synchronize];
}

当我调用setObject:forKey时,我的应用程序会冻结。如果我在那一行添加一个断点,继续运行,它就会工作。如果我不打破,它就会结冰。

这是在我将Xcode更新到版本8并开始使用新的SDK之后发生的。有什么线索吗?

我在几个应用程序中也遇到了这个问题——似乎通过mutableArrayValueForKey返回可变数组,您可能会陷入互斥锁。对于我的代码,我将其替换为:

  • 获取一个不可变数组为NSArray*arrSource=[defaults arrayForKey:strKey]
  • 将数据复制到可变数组中:NSMutableArray*arrMutable=[NSMutableArray arrayWithArray:arrSouce]
  • 正在arrMutable中设置我的值
  • 将"修改后"的阵列存储回默认值:[默认设置对象:arrMutable forKey:strKey]

至少对我来说,这已经解决了互斥锁的问题。

经过实验,我找到了生成互斥锁所需的最低代码。代码如下。

NSMutableArray *videoArray = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:VIDEOKEY];
[videoArray addObject:item];
[[NSUserDefaults standardUserDefaults] setObject:videoArray forKey:VIDEOKEY];

有三点需要注意:

  1. 如果我删除[videoArray addObject:item];,应用程序将崩溃
  2. 互斥锁发生在[[NSUserDefaults standardUserDefaults] setObject:videoArray forKey:VIDEOKEY];
  3. 如果我在[videoArray addObject:item];上设置了一个断点,那么互斥锁仍然存在。如果我在[[NSUserDefaults standardUserDefaults] setObject:videoArray forKey:VIDEOKEY];上进行,互斥锁将不存在

可以推断互斥锁是由[NSKeyValueSlowMutableArray addObject:];[NSUserDefaults setObject:forKey:]造成的

顺便说一句,我的解决方案如下:

NSMutableArray *mutableVideoArray;
NSArray *videoArray = [[NSUserDefaults standardUserDefaults] arrayForKey:VIDEOKEY];
if (videoArray)
     mutableVideoArray = [videoArray mutableCopy];
else
    mutableVideoArray = [NSMutableArray array];
if (![mutableVideoArray containsObject:item])
{
    [mutableVideoArray addObject:item];
    [[NSUserDefaults standardUserDefaults] setObject:mutableVideoArray forKey:VIDEOKEY];
}

最新更新