2013-05-24 3 views
7

У меня есть класс, который содержит NSSet. Этот объект называется _collectibles, а в методе, я делаю копию этого набора для того, чтобы сделать некоторую обработку, что-то вроде:Bizarre 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] более эффективен, и я бы предпочел использовать его, но я не могу понять, почему он абсолютно воинственный!

Update: в то время как полный контекст бы тонну объяснения, ключи мне Решая это было то, что, а, код был вызван таким образом:

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

[operationQueue addOperation: operation]; 

И что я, в основном, сделав куча вещей медленнее, поймать приложение 2 потоков, выполняющихся 2 темы для очереди инициализируется таким образом:

operationQueue.maxConcurrentOperationCount = 1; 

который я думал, невозможно. Подсказка заключалась в том, что вторая нить была в [NSAutoreleasePool drain], которая привела меня к тому, что NSOperationQueue может делать материал autorelease всякий раз, когда он хочет.

+0

Я не смог воспроизвести вашу ошибку. Не могли бы вы разместить немного кода для контекста? – aLevelOfIndirection

+0

- это набор, в котором вы копируете взаимосвязь данных ядра? –

+0

Весь контекст потребует огромной кучи кода. :) – GoldenBoy

ответ

2

Would

NSSet* collectibleCopy = [NSSet setWithSet:_collectibles] 

работа для вас?

+0

Это может быть ... Я предполагаю, что причина, по которой она не сработала (см. Мой другой ответ), была чем-то вроде семантики быстрой итерации против того, что NSSet делает для протокола NSCopying. – GoldenBoy

2

ОК, поэтому huzzah за то, что на самом деле понял это.

Трюк здесь заключался в том, что эта операция выполнялась на асинхронном NSOperationQueue. TIL, которые NSOperationQueues имеют AutoreleasePools, но что они истощаются по усмотрению GCD. В этом случае пул из предыдущей операции одновременно сливается с другим потоком, что приводит к довольно непрозрачной проблеме одновременной модификации.

Решение:

@autoreleasepool внутри блока, на котором этот код был вызван. Это приводит к тому, что утечка происходит как часть блока, а не асинхронно, и мое состояние гонки уходит.