Как получается, что класс графического интерфейса какао запускается без вызова NSApplication или NSRunLoop

Почему работает следующий код? Это небольшая программа Cocoa, которая использует NSOpenPanel для выбора файла и открытия его в Emacs.app. Его можно запустить из командной строки с начальным каталогом в качестве аргумента.

Как работает NSOpenPanel без вызова NSApplication или NSRunLoop? Каковы ограничения для программы Какао, которая явно не запускает NSApplication или NSRunLoop? Я бы подумал, что одна из них: вы не можете использовать какой-либо графический интерфейс. Возможно, при вызове 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"];
  }
}

person Colin    schedule 08.04.2014    source источник


Ответы (1)


_ 1_ создает и запускает собственный цикл обработки событий. Из документации:

Отображает панель и начинает цикл модальных событий, который завершается, когда пользователь нажимает кнопку «ОК» или «Отмена».

Вы также можете увидеть это, если приостановите программу, пока активно диалоговое окно «Открыть», и распечатайте трассировку стека в консоли отладчика:

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, _ 3_ используется для запуска модального цикла событий для диалогового окна« Открыть ».

person Martin R    schedule 08.04.2014
comment
Да я вижу. Спасибо за быстрый ответ. Я только что понял, что старый классический Apple main.m вызывает [NSApplication sharedApplication], а не [NSApplication allocation]. Я предполагаю, что вызову runModalForWindow могло предшествовать создание экземпляра синглтона [NSApplication sharedApplication] в библиотеке Apple. - person Colin; 08.04.2014