【问题标题】:Objective-C completion block causing extra method call?Objective-C完成块导致额外的方法调用?
【发布时间】:2011-09-11 17:58:43
【问题描述】:

这是一个奇怪的问题。我的应用程序向控制硬件设备的对象发送关闭消息,并以完成块作为参数。关闭消息返回一个 BOOL,这取决于它是否能够立即完成关闭。所以 YES 表示现在已经完成,NO 表示稍后完成时会调用完成处理程序。

这是主控制器代码:

- (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: 再次被调用?我认为必须。有没有更好的方法在完成处理程序中退出应用程序?

【问题讨论】:

    标签: objective-c cocoa objective-c-blocks


    【解决方案1】:

    既然您找到了问题的根本原因(调用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;          
    }
    

    【讨论】:

    • 无赖。这实际上不起作用。这会导致运行循环进入 NSModalPanelRunLoopMode,这意味着我的应用程序没有在运行循环上得到它的 AsyncSocket 调用,因此我无法与设备通信以使其关闭。我必须将其移至另一个运行循环,这比避免第二次调用更值得。
    • 我从 AsyncSocket 的 Run Loop 版本切换到 GCD 版本,现在我可以在终止挂起时完成我的设备控制器代码。
    猜你喜欢
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多