Ваш dataUpdated
метод использует dispatch_sync
для вызова основного потока:
- (void) DataUpdated
{
dispatch_sync(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"DataUpdateNotification" object:self];
});
}
Вы хотите убедиться, что это уведомление отправляется только в главном потоке, что является хорошей идеей. Проблема возникает, когда, как ясно видно из обратной трассировки, этот метод отправляется из основного потока. Легко понять, почему это проблема; dispatch_sync
ждет, пока блок, который вы передаете, завершится, но если вы попытаетесь запустить блок в главной очереди, и основной поток блокирует, ожидая завершения dispatch_sync
, основной поток собирается быть заблокированным навсегда, и ваше приложение по сути зависло. Теперь, почему происходит сбой с EXC_BAD_INSTRUCTION
Я не уверен, но он делает это и на моей машине, когда я пытаюсь это сделать. Я почти уверен, что он просто завис в первый раз, когда я сделал это случайно, как малышка, так что кто знает. Возможно, в какой-то момент они добавили некоторую защиту, чтобы обнаружить этот сценарий и просто потерпеть крах, чтобы вы могли получить хороший след, чтобы выяснить, что произошло.
В любом случае, нам просто нужно избегать блокировки основного потока во время ожидания основного потока. Если вы dispatch_async
вместо dispatch_sync
, это будет прекрасно работать:
- (void) DataUpdated
{
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"DataUpdateNotification" object:self];
});
}
dispatch_async
не блокируется в ожидании завершения блока, поэтому не блокируется. Плохая новость заключается в том, что уведомление не будет запущено немедленно; это будет ждать до следующего вращения цикла событий. Если это проблема, просто проверьте основной поток, например:
- (void) DataUpdated
{
// hopefully my skills at remembering the $@#%ing block syntax haven't
// atrophied due to primarily writing Swift lately
void (^sendIt)(void) = ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"DataUpdateNotification" object:self];
};
if ([NSThread isMainThread]) {
sendIt();
} else {
dispatch_sync(dispatch_get_main_queue(), sendIt);
}
}
Это гарантирует, что уведомление всегда отправляется немедленно, а метод всегда ждет, пока не закончится отправка. Если вы делаете такие вещи часто, вы можете написать выше, как служебную функцию, которая берет произвольный блок и запускает его синхронно в главном потоке.