Подтвердить что ты не робот

Правильное управление 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 из этого блока, поэтому это не может быть прав.

4b9b3361

Ответ 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 в окне консоли после сбоя приложения даст вам обратную трассировку и должен сообщить вам, где произошла ошибка.