Блок завершения Objective-C вызывает дополнительный вызов метода? - PullRequest
4 голосов
/ 11 сентября 2011

Вот странный.Мое приложение отправляет сообщение о завершении работы объекту, управляющему аппаратным устройством, с блоком завершения в качестве аргумента.Сообщение о завершении работы возвращает BOOL, в зависимости от того, удалось ли ему завершить работу немедленно.Таким образом, ДА означает, что это сделано сейчас, НЕТ означает, что он вызовет обработчик завершения, когда это будет сделано позже.

Вот основной код контроллера:

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{               
BOOL shutdownNow = [theStoker shutdownWithCompletionHandler:^(void) 
{
    NSLog(@"applicationShouldTerminate: completionBlock");
    [[NSRunningApplication currentApplication] terminate];
}];

if (!shutdownNow)
{
    NSLog(@"applicationShouldTerminate: waiting for shutdown");
    return NSTerminateCancel;   
}
return NSTerminateNow;          
}

Вот код контроллера устройства:

- (BOOL)shutdownWithCompletionHandler:(void (^)(void))handler 
{
if (busy)
{
    self.completionBlock = handler;
    [self stopDevice];
    NSLog(@"shutdownWithCompletionHandler: Wait for reset");
    return NO;
}

NSLog(@"Stoker: shutdownWithCompletionHandler: shutdown now");
return YES;
}

Странная часть в том, что сообщения о выключении нужно отправлять дважды.Это сообщения NSLog:

shutdownWithCompletionHandler: Wait for reset
applicationShouldTerminate: waiting for reset
applicationShouldTerminate: completionBlock
shutdownWithCompletionHandler: shutdown now

Таким образом, после выполнения блока завершения я возвращаюсь обратно в метод shutdownWithCompletionHandler: объекта устройства.Почему?

Править: Хммм.Вызывает ли [[NSRunningApplication currentApplication] terminate]; повторный вызов applicationShouldTerminate:?Я думаю, что это должно.Есть ли лучший способ выйти из приложения в обработчике завершения?

1 Ответ

5 голосов
/ 11 сентября 2011

Поскольку вы нашли основную причину вашей проблемы (вызов terminate вызывает applicationShouldTerminate:), вот как ее избежать.

Вместо отмены завершения, верните NSTerminateLater, когда оно будетотключение позже.Затем ваш блок завершения должен вызвать [NSApp replyToApplicationShouldTerminate:YES], чтобы вызвать завершение, без повторного вызова applicationShouldTerminate:.

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {               
    BOOL shutdownNow = [theStoker shutdownWithCompletionHandler:^(void)  {
        NSLog(@"applicationShouldTerminate: completionBlock");
        [NSApp replyToApplicationShouldTerminate:YES];
    }];

    if (!shutdownNow) {
        NSLog(@"applicationShouldTerminate: waiting for shutdown");
        return NSTerminateLater;
    }
    return NSTerminateNow;          
}
...