我有一个使用bk_apply
构建NSMutableDictionary
的函数,BlocksKit是第三方块实用程序库documentation提供的方法。该函数的测试套件通常可以正常通过,但每次运行它都会崩溃。
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
[inputSet bk_apply:^(NSString *property) {
NSString *localValueName = propertyToLocalName[property];
NSObject *localValue = [self valueForKey:localValueName];
result[property] = localValue ?: defaults[property]; // Crash
// Convert all dates in result to ISO 8601 strings
if ([result[property] isKindOfClass:[NSDate class]]) { // Crash
result[property] = ((NSDate *)result[property]).ISODateString; // Crash
}
}];
崩溃总是发生在引用result
的行上,但每次都不是同一行。
检查调试器中result
的内容,我发现了很奇怪的值,比如
po result
{
val1 = "Some reasonable value";
val2 = "Also reasonable value";
(null) = (null);
}
NSDictionary
无法拥有null
个键或值,因此很明显会违反某些不变量。
造成此次崩溃的原因是什么?如何解决?
答案 0 :(得分:2)
来自BlocksKit thread scheduler的bk_apply
:
枚举将在适当的后台队列上进行。这将 有明显的速度提升,特别是在双核设备上,但是 您必须了解您发送的对象的线程安全性 在街区内。
上面的代码在线程方面非常不安全,因为它在多个线程上读取和写入可变变量。
崩溃的间歇性来自于bk_each
是非确定性的事实。当多个线程访问共享内存发生以按顺序而不是并行安排执行时,崩溃不会发生。因此可以“幸运”#34;一些甚至大部分时间,但代码仍然是错误的。
调试器打印输出是危险的一个很好的例子。暂停的线程最有可能从result
读取,而另一个线程执行插入。
NSMutableDictionary
插入可能不是原子的;示例步骤可能是,
如果您从步骤 1 和 2 之间的其他线程中读取字典,您将看到已分配内存的条目,但内存中不包含任何值。
最简单的解决方法是切换到{{3}}。 bk_each
与bk_apply
做同样的事情,但它以保证顺序执行的方式实现。