Почему я получаю NSFastEnumerationMutationHandler в коде, который не изменяет исходный массив / набор?

В моих журналах сбоев для моей последней версии приложения я получил NSFastEnumerationMutationHandler с последующим аварийным обращением HKAnchoredObjectQuery initWithType для моего кода, но я не намеренно мутировал NSMutableSet sources по которому я быстро перечисляю.

Вот мой код:

    for(HKSource* source in sources){
        NSPredicate *predicate = [HKQuery predicateForObjectsFromSources:[NSSet setWithObject:source]];
        HKAnchoredObjectQuery *newQuery = [[HKAnchoredObjectQuery alloc] initWithType:quantityType predicate:predicate anchor:anchor limit:HKObjectQueryNoLimit completionHandler:^(HKAnchoredObjectQuery *query, NSArray *results, NSUInteger newAnchor, NSError *error) {
            completion(results);
        }];

        [healthStore executeQuery:newQuery];
    }

Любые предложения о том, почему я запускаю NSFastEnumerationMutationHandler? Я не касаюсь явно sources и я не сделал его копию... есть ли способ HealthKit может быть изменение source? Даже если бы это было, я думаю, что изменение source не должен вызывать это, поскольку я не касаюсь напрямую sources, Любые советы по устранению неполадок или обнаружению ошибок будут высоко оценены.

Вот точный текст из журнала сбоя:

Latest Exception Backtrace:
1. libobjc.A.dylib     objc_exception_throw
2. CoreFoundation      _NSFastEumerationMutationHandler
3. App name             0x1000d8000
4. App name             0x1000d8000
5. App name             0x1000d8000
6. HealthKit           _79-[HKAnchoredObjectQuery initWithType:predicate:anchor:limit:completionHandler:]_block_invoke     <---this must be referring to my code above, as it's the only call to initWithType inside a fast enumeration
7. HealthKit           _81-[HKAnchoredObjectQuery deliverSampleObjects:deletedObjects:withAnchor:forQuery:]_block_invoke_2     <-- this is an internal HealthKit call. deliverSampleObjects is not a publicly listed method of the interface.

У меня не было сбоев в симе или на моем телефоне, так что это единственная информация, на которую я должен перейти.

2 ответа

Решение

Некоторый код, который вызывается блоком с именем completion() в вашем коде фрагмент перебирает другую коллекцию и делает это во время изменения этого массива. Имейте в виду, что completionHandler из HKAnchoredObjectQuery выполняется в фоновом потоке, поэтому ваш код может выполнять небезопасные параллельные операции над объектами, когда completionHandler вызывается.

Похоже, это происходит в блоке где-то в методе с именем

[HKAnchoredObjectQuery initWithType:predicate:anchor:limit:completionHandler:]

Таким образом, я предполагаю, что рассматриваемый блок является обработчиком завершения, и обработчик завершения вызывается асинхронно - в то время как кто-то другой выполняет итерацию по тому же массиву и, возможно, модифицирует его.

К сожалению, эта ошибка не показывает, кто вызывает проблему, а только кто ее находит. Я бы установил точку останова для вашего собственного обратного вызова, проверил бы, вызывается ли он из быстрого перечисления, и попытался бы выяснить, кто еще может изменять данные. Удачи.

Другие вопросы по тегам