2014-04-08 66 views
5

爲什麼下面的代碼有效?這是一個小型的Cocoa程序,它使用NSOpenPanel選擇一個文件並在Emacs.app中打開它。它可以從起始目錄作爲參數在命令行中運行。Cocoa GUI類如何在不調用NSApplication或NSRunLoop的情況下運行

NSOpenPanel如何在不調用NSApplication或NSRunLoop的情況下運行?對於沒有明確啓動NSApplication或NSRunLoop的Cocoa程序有什麼限制?我原以爲其中之一是:你不能使用任何一種GUI。也許通過調用NSOpenPanel,調用一些調用NSRunLoop的後備代碼?我在+ [NSApplication alloc]和+ [NSRunLoop alloc]上放置了斷點,它們沒有被觸發。

main.m: 

#import <Cocoa/Cocoa.h> 

NSString *selectFileWithStartPath(NSString *path) { 
    NSString *answer = nil; 
    NSOpenPanel* panel = [NSOpenPanel openPanel]; 
    panel.allowsMultipleSelection = NO; 
    panel.canChooseFiles = YES; 
    panel.canChooseDirectories = NO; 
    panel.resolvesAliases = YES; 
    if([panel runModalForDirectory:path file:nil] == NSOKButton) 
    answer = [[[panel URLs] objectAtIndex:0] path]; 
    return answer; 
} 

int main(int argc, const char * argv[]) { 
    NSString *startPath = argc > 1 ? [NSString stringWithUTF8String:argv[1]] : @"/Users/Me/Docs"; 
    printf("%s\n", argv[1]); 
    BOOL isDir; 
    if([[NSFileManager defaultManager] fileExistsAtPath:startPath isDirectory:&isDir] && isDir) { 
    system([[NSString stringWithFormat:@"find %@ -name \\*~ -exec rm {} \\;", startPath] UTF8String]); 
    NSString *file = selectFileWithStartPath(startPath); 
    if(file) [[NSWorkspace sharedWorkspace] openFile:file withApplication:@"Emacs.app"]; 
    } 
} 

回答

5

runModalForDirectory:file:types:創建並運行自己的事件循環。 從文檔:

顯示面板,並開始一個模態事件循環終止 當用戶點擊確定或取消。

你可以看到,如果你還暫停節目,而「打開」對話框活動 並打印在調試器控制檯中的堆棧跟蹤:

frame #0: 0x00007fff8b855a1a libsystem_kernel.dylib`mach_msg_trap + 10 
frame #1: 0x00007fff8b854d18 libsystem_kernel.dylib`mach_msg + 64 
frame #2: 0x00007fff8549f155 CoreFoundation`__CFRunLoopServiceMachPort + 181 
frame #3: 0x00007fff8549e779 CoreFoundation`__CFRunLoopRun + 1161 
frame #4: 0x00007fff8549e0b5 CoreFoundation`CFRunLoopRunSpecific + 309 
frame #5: 0x00007fff88381a0d HIToolbox`RunCurrentEventLoopInMode + 226 
frame #6: 0x00007fff883817b7 HIToolbox`ReceiveNextEventCommon + 479 
frame #7: 0x00007fff883815bc HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 65 
frame #8: 0x00007fff838ca3de AppKit`_DPSNextEvent + 1434 
frame #9: 0x00007fff838c9a2b AppKit`-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122 
frame #10: 0x00007fff83c28e2e AppKit`-[NSApplication _realDoModalLoop:peek:] + 642 
frame #11: 0x00007fff83c2754e AppKit`-[NSApplication runModalForWindow:] + 117 
frame #12: 0x00007fff83ef5d0b AppKit`-[NSSavePanel runModal] + 276 
frame #13: 0x0000000100000c61 xxx`selectFileWithStartPath(path=0x00000001000010b8) + 225 at main.m:18 
frame #14: 0x0000000100000e0d xxx`main(argc=1, argv=0x00007fff5fbff9c0) + 189 at main.m:26 

正如你可以在幀#11看,-[NSApplication runModalForWindow:]用於運行「打開」對話框的模式 事件循環。

+0

是的,我明白了。感謝您的快速響應。我剛剛意識到的一件事是,舊的經典Apple main.m調用[NSApplication sharedApplication],而不是[NSApplication alloc]。我猜測對runModalForWindow的調用可能已經在Apple庫中實例化了一個單例[NSApplication sharedApplication]。 – Colin

相關問題