2014-04-08 19 views
5

Warum funktioniert der folgende Code? Es ist ein kleines Cocoa-Programm, das NSOpenPanel verwendet, um eine Datei auszuwählen und sie in Emacs.app zu öffnen. Es kann von der Kommandozeile mit dem Startverzeichnis als Argument ausgeführt werden.Wie wird die Cocoa-GUI-Klasse ausgeführt, ohne dass NSApplication oder NSRunLoop aufgerufen werden?

Wie läuft NSOpenPanel, ohne NSApplication oder NSRunLoop aufzurufen? Welche Einschränkungen gibt es für ein Cocoa-Programm, das NSApplication oder NSRunLoop nicht explizit startet? Ich hätte gedacht, einer von ihnen wäre: Sie können keine GUI verwenden. Vielleicht wird durch Aufrufen von NSOpenPanel ein Fallback-Code aufgerufen, der NSRunLoop aufruft. Ich habe Breakpoints auf + [NSApplication] und + [NSRunLoop alloc] gesetzt und sie wurden nicht ausgelöst.

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"]; 
    } 
} 

Antwort

5

runModalForDirectory:file:types: erstellt und führt eine eigene Ereignisschleife aus. Aus der Dokumentation:

Zeigt die Tafel und beginnt eine modale Ereignisschleife, die beendet wird, wenn der Benutzer entweder OK oder Abbrechen klickt.

Sie können sehen, dass auch wenn Sie das Programm anhalten, während der Dialog „Öffnen“ aktiv ist und den Stapel Backtrace in der Debugger-Konsole aus:

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 

Wie Sie im Rahmen # sehen 11 , -[NSApplication runModalForWindow:] wird verwendet, um eine modale Ereignisschleife für den "Öffnen" -Dialog auszuführen.

+0

Ja, ich verstehe. Danke für die schnelle Antwort. Eine Sache, die ich gerade realisiert habe, ist, dass der alte klassische Apple main.m [NSApplication sharedApplication] aufruft, nicht [NSApplication allocate]. Ich nehme an, dass dem Aufruf von runModalForWindow möglicherweise zuvor ein Singleton [NSApplication sharedApplication] in der Apple-Bibliothek instanziiert wurde. – Colin