我有一个包含NSSet
的课程。该对象称为_collectibles
,在一个方法中,我制作该集的副本以进行某些处理,如:
NSSet* collectibleCopy = [_collectibles copy];
在实践中,我看到这个消息经常崩溃:
[__NSPlaceholderSet initWithObjects:count:]: attempt to insert nil object from objects
我已通过将上述代码更改为:
解决了该问题NSMutableSet* collectibleCopy = [[NSMutableSet alloc] initWithCapacity: [_collectibles count]];
for ( id thing in _collectibles ) {
[collectibleCopy addObject: thing];
}
现在我再也无法重现任何此类崩溃。我打赌[copy]
更有效率,我宁愿使用它,但我无法弄清楚为什么它完全不受欢迎!
更新:虽然完整的上下文需要大量的解释,但解决这个问题的关键是,a,代码是这样调用的:
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock: ^{
[thing doStuff];
}];
[operationQueue addOperation: operation];
我是,基本上是通过使一堆事情变得更慢,抓住应用程序用2个线程运行2个线程为这样的队列初始化:
operationQueue.maxConcurrentOperationCount = 1;
我认为这是不可能的。线索是第二个线程在[NSAutoreleasePool drain]中,这让我得知NSOperationQueue可以随时随地进行自动释放。
答案 0 :(得分:2)
会
NSSet* collectibleCopy = [NSSet setWithSet:_collectibles]
为你工作?
答案 1 :(得分:2)
好的,所以你真的想出来了。
这里的诀窍是此操作是在异步NSOperationQueue
上执行的。 TIL认为NSOperationQueues有AutoreleasePools,但它们会被GCD酌情决定。在这种情况下,前一个操作的池正在同时在另一个线程上耗尽,导致相当不透明的并发修改问题。
解决方案:
调用此代码的块内的 @autoreleasepool
。这导致排水发生在街区的一部分,而不是异步,我的竞争条件就消失了。