7

我有一个包含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 可以随时随地进行自动释放。

4

2 回答 2

2

好的,所以真的想出来了。

这里的技巧是这个操作是在 async 上执行的NSOperationQueue。直到 NSOperationQueues 具有 AutoreleasePools,但是它们会在 GCD 的判断下被耗尽。在这种情况下,来自先前操作的池同时在另一个线程上耗尽,从而导致相当不透明的并发修改问题。

解决方案:

@autoreleasepool在调用此代码的块内。这会导致耗尽作为块的一部分发生,而不是异步发生,并且我的竞争条件消失了。

于 2013-05-24T16:00:34.343 回答
2

NSSet* collectibleCopy = [NSSet setWithSet:_collectibles] 

为你工作?

于 2013-05-24T14:21:38.067 回答