Правильное управление addObserverForName: object: queue: usingBlock:
Я все еще новичок в блоках в objective-c и задаюсь вопросом, правильно ли у меня этот код psuedo. Я не уверен, достаточно ли этого, чтобы просто удалить наблюдателя или мне нужно вызвать removeObserver: name: object:
-(void) scan {
Scanner *scanner = [[Scanner alloc] init];
id scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete"
object:scanner
queue:nil
usingBlock:^(NSNotification *notification){
/*
do something
*/
[[NSNotificationCenter defaultCenter] removeObserver:scanComplete];
[scanner release];
}];
[scanner startScan];
}
Обновление: я получаю прерывистый EXC_BAD_ACCESS
из этого блока, поэтому это не может быть прав.
Ответы
Ответ 1
Объявите переменную scanComplete
перед определением самого блока.
Причина, по которой вам нужно сделать это, заключается в том, что вы пытаетесь получить доступ к переменной, которая не существует в блоке во время определения, поскольку сама переменная еще не назначена.
Что такое EXC_BAD_ACCESS
? Ну, это исключение, которое бросается, когда вы пытаетесь получить доступ к ссылке, которая не существует. Так что это именно так в вашем примере.
Итак, если вы объявляете переменную перед самим блоком, то она должна работать:
-(void) scan {
Scanner *scanner = [[Scanner alloc] init];
__block id scanComplete;
scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete"
object:scanner
queue:nil
usingBlock:^(NSNotification *notification){
/*
do something
*/
[[NSNotificationCenter defaultCenter] removeObserver:scanComplete];
[scanner release];
}];
[scanner startScan];
}
Ответ 2
Вы не должны отменить регистрацию в блоке регистров. Вместо этого сохраните токен, возвращенный из addObserverForName
(в данном случае, ваш scanComplete
) в качестве переменной экземпляра или в коллекции, являющейся переменной экземпляра, и отмените регистрацию позже, когда вы собираетесь выйти из строя (например, в dealloc
). Я использую NSMutableSet под названием observers
. Итак:
id ob = [[NSNotificationCenter defaultCenter]
addObserverForName:@"whatever" object:nil queue:nil
usingBlock:^(NSNotification *note) {
// ... whatever ...
}];
[self->observers addObject:ob];
И потом:
for (id ob in self->observers)
[[NSNotificationCenter defaultCenter] removeObserver:ob];
self->observers = nil;
Ответ 3
Apple Документ об этом методе:
В следующем примере показано, как вы можете зарегистрироваться для получения уведомлений об изменении локали.
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
self.localeChangeObserver = [center addObserverForName:NSCurrentLocaleDidChangeNotification object:nil
queue:mainQueue usingBlock:^(NSNotification *note) {
NSLog(@"The user locale changed to: %@", [[NSLocale currentLocale] localeIdentifier]);
}];
Чтобы отменить регистрацию наблюдений, вы передаете объект, возвращенный этим методом, для удаленияObserver:. Вы должны вызывать removeObserver: или removeObserver: name: object: перед любым объектом, указанным addObserverForName: object: queue: usingBlock: освобождается.
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self.localeChangeObserver];
Ответ 4
Объем блока не имеет разрешения на выпуск объекта сканера. Если вы не используете сбор мусора, удаление release
и создание авторекламы сканера ([[[Scanner alloc] init] autorelease]
) должно сделать трюк.
Вы также можете безопасно перевести вызов на removeObserver
вне блока.
В случае EXC_BAD_ACCESS
: Ввод bt
в окне консоли после сбоя приложения даст вам обратную трассировку и должен сообщить вам, где произошла ошибка.