Почему я получаю 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:]
Таким образом, я предполагаю, что рассматриваемый блок является обработчиком завершения, и обработчик завершения вызывается асинхронно - в то время как кто-то другой выполняет итерацию по тому же массиву и, возможно, модифицирует его.
К сожалению, эта ошибка не показывает, кто вызывает проблему, а только кто ее находит. Я бы установил точку останова для вашего собственного обратного вызова, проверил бы, вызывается ли он из быстрого перечисления, и попытался бы выяснить, кто еще может изменять данные. Удачи.