2013-05-24 10 views
7

Ich habe eine Klasse, die eine NSSet enthält. Diese Aufgabe wird _collectibles genannt, und in einem Verfahren, mache ich eine Kopie dieses Satzes um einige Verarbeitung, so etwas wie zu tun:Bizarre NSSet Kopieren Absturz

NSSet* collectibleCopy = [_collectibles copy]; 

In der Praxis sehe ich regelmäßig mit dieser Meldung abstürzen:

[__NSPlaceholderSet initWithObjects:count:]: attempt to insert nil object from objects 

ich habe das Problem gelöst, indem Sie den obigen Code zu ändern zu:

NSMutableSet* collectibleCopy = [[NSMutableSet alloc] initWithCapacity: [_collectibles count]]; 
for (id thing in _collectibles) { 
    [collectibleCopy addObject: thing]; 
} 

Und jetzt kann ich nicht reproduzieren mehr einen solchen Absturz. Ich wette, [copy] ist effizienter, und ich würde es lieber verwenden, aber ich kann nicht herausfinden, warum es völlig wonky ist!

Update: während voller Kontext eine Tonne Erklärung nehmen würde, die Schlüssel zu mir dieser Lösung waren, dass ein, der Code auf diese Weise aufgerufen wurde:

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

[operationQueue addOperation: operation]; 

Und das war ich, im Grunde durch eine Herstellung Haufen Dinge langsamer, fangen die App mit 2 Fäden laufen 2 Fäden für eine Warteschlange thusly initialisiert:

operationQueue.maxConcurrentOperationCount = 1; 

was ich dachte, unmöglich. Der Hinweis war, dass der zweite Thread in [NSAutoreleasePool drain] war, was mich dazu brachte, zu erfahren, dass NSOperationQueue immer dann Autorelease-Sachen machen kann, wenn es will.

+0

Ich konnte Ihren Fehler nicht reproduzieren. Könntest du etwas mehr Code für den Kontext posten? – aLevelOfIndirection

+0

ist der Satz, den Sie eine Kerndatenbeziehung kopieren? –

+0

Der gesamte Kontext würde einen riesigen Stapel von Code erfordern. :) – GoldenBoy

Antwort

2

Would

NSSet* collectibleCopy = [NSSet setWithSet:_collectibles] 

Arbeit für Sie?

+0

Es könnte sein - ich vermute, der Grund, warum es nicht abstürzte (siehe meine andere Antwort) war etwas über die Semantik der schnellen Iteration vs. was auch immer NSSet für das NSCopying-Protokoll tut. – GoldenBoy

2

OK, also huzzah, das tatsächlich herausgefunden zu haben.

Der Trick hier war, dass diese Operation auf einem asynchronen NSOperationQueue durchgeführt wurde. TIL, dass NSOperationQueues AutoreleasePools haben, aber dass sie im Ermessen von GCD ausgelaufen sind. In diesem Fall wurde der Pool aus einer vorherigen Operation gleichzeitig in einem anderen Thread gelöscht, was zu einem eher undurchsichtigen Problem der gleichzeitigen Änderung führt.

Lösung:

@autoreleasepool innerhalb des Blocks, auf dem wurde dieser Code aufgerufen. Dies führt dazu, dass der Abfluss als Teil des Blocks und nicht asynchron passiert und mein Race-Zustand verschwindet.