我有一个存储到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];
有三点需要注意:
- 如果我删除
[videoArray addObject:item];
,应用程序将崩溃 - 互斥锁发生在
[[NSUserDefaults standardUserDefaults] setObject:videoArray forKey:VIDEOKEY];
中 - 如果我在
[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];
}