2011-09-11 21 views
4

這是一個奇怪的。我的應用程序將一個關閉消息發送給一個控制硬件設備的對象,並將一個完成塊作爲參數。關閉消息返回一個BOOL,取決於它是否能夠立即完成關閉。所以YES意味着它現在完成了,NO表示它將在稍後完成時調用完成處理程序。Objective-C完成塊導致額外的方法調用?

這裏的主控制器的代碼:

- (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:再次被調用?我認爲它必須。是否有更好的方式在完成處理程序中退出應用程序?

回答

5

由於您發現問題的根本原因(致電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;   
} 
+0

非常好,謝謝! – Flyingdiver

+0

無賴。這實際上並不奏效。這會導致運行循環進入NSModalPanelRunLoopMode,這意味着我的應用程序沒有在運行循環中獲取它的AsyncSocket調用,所以我無法與設備進行通信以使其關閉。我必須將其移至另一個運行循環,這比避免第二次調用的值得多。 – Flyingdiver

+0

我從AsyncSocket的Run Loop版本切換到GCD版本,現在我可以在終止處於掛起狀態時完成設備控制器代碼。 – Flyingdiver

相關問題