2013-05-24 2 views
7

私はNSSetを含むクラスを持っています。そのオブジェクトは_collectiblesと呼ばれ、この方法では、私は、いくつかの処理を行うためにのようなものをそのセットのコピーを作成します奇妙なNSSetのコピークラッシュ

:実際には、私はこれは定期的にこのメッセージを表示してクラッシュを参照

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]がより効率的であると賭けています。私はむしろそれを使用したいと思いますが、なぜそれが完全にうんざりしているのか理解できません!

更新:

NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock: ^{ 
    [thing doStuff]; 
}]; 

[operationQueue addOperation: operation]; 

そして、私は基本的に行うことで、だったもの:フルコンテキストは説明のトンを取るだろうが、これを解決する私に鍵は、コードがこのように呼び出された、ということでした2つのスレッドで2つのスレッドを実行して、キューに入れてアプリをキャッチする:

operationQueue.maxConcurrentOperationCount = 1; 

私は不可能だと思った。手掛かりは、2番目のスレッドが[NSAutoreleasePool drain]に入っていて、NSOperationQueueが必要なときにいつでもオートレリースの処理ができることを知ることができました。

+0

私はあなたのバグを再現できませんでした。文脈のためにもう少しコードを投稿できますか? – aLevelOfIndirection

+0

は、コアデータの関係をコピーするセットですか? –

+0

コンテキスト全体が膨大な量のコードを必要とします。 :) – GoldenBoy

答えて

2

NSSet* collectibleCopy = [NSSet setWithSet:_collectibles] 

仕事あなたのために?

+0

これは、NSSがNSCopyingプロトコルのために行うものとは異なり、速い反復のセマンティクスに関するものでした(私の他の答えを参照してください)クラッシュしなかった理由を推測しているかもしれません。 – GoldenBoy

2

OK、これを実際に把握してくれたので、

この操作は、非同期のNSOperationQueueで実行されました。 TILはNSOperationQueuesがAutoreleasePoolsを持っていますが、GCDの裁量で排水されます。この場合、以前の操作のプールが別のスレッドで同時に排水されていました。その結果、不透明な並行変更の問題が発生しました。

ソリューション:このコードが呼び出されてしまったブロック内の

@autoreleasepool。これにより、非同期ではなくブロックの一部としてドレインが発生し、競合状態が解消されます。