Не удается найти поток графического интерфейса Cocoa в приложении C++ с графическим интерфейсом Objective-C++

У меня есть многопоточное приложение Linux C++ без графического интерфейса, в котором я хочу иметь возможность использовать случайный элемент управления Cocoa, а именно диалоги загрузки/выгрузки файлов и предупреждение.

Я далек от эксперта по Cocoa, но смог создать несколько тестовых/демонстрационных приложений на Objective-C++, которые работали, как задумано.

Теперь, когда я интегрировал код Cocoa в свое приложение, у меня возникли проблемы с публикацией данных в основной поток графического интерфейса. Может быть, я не сделал того, что нужно было сделать для его создания, я действительно не уверен. Вот что у меня есть в моем .mm файле:

#ifdef MACOS
@interface CocoaInterface : NSObject
{
}
- (id) init;
- (void) ShowFileUploadDialog;
- (void) ShowFileDownloadDialog;
@end

@implementation CocoaInterface
- (id) init
{
    cout << "Creating NSAutoreleasePool" << endl;
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    cout << "Creating NSApplication" << endl;
    NSApplication* app = [[NSApplication alloc] init];
    cout << "Calling NSApplication::finishLaunching" << endl;
    [app finishLaunching];
    [super init];
    return self;
}

- (void) ShowFileUploadDialog
{
    cout << "Entering ShowFileUploadDialog" << endl;
    if ([NSThread isMainThread])
    {
        // Show file dialog
        cout << "Calling NSRunAlertPanel" << endl;
        NSRunAlertPanel(@"This is a test", @"Does it work?", @"Yes", @"No", @"");
    }
    else 
    {
        //NSRunAlertPanel(@"This is a test", @"Does it work?", @"Yes", @"No", @"");
        cout << "Redirecting ShowFileUploadDialog call to main thread." << endl;
        [self performSelectorOnMainThread:@selector(ShowFileUploadDialog) withObject:nil waitUntilDone:YES];
    }
}

- (void) ShowFileDownloadDialog
{
    cout << "Entering ShowFileDownloadDialog" << endl;
    if ([NSThread isMainThread])
    {
        // Show file dialog
        cout << "Calling NSRunAlertPanel" << endl;
        NSRunAlertPanel(@"This is a test", @"Does it work?", @"Yes", @"No", @"");
    }
    else
    {
        //NSRunAlertPanel(@"This is a test", @"Does it work?", @"Yes", @"No", @"");
        cout << "Redirecting ShowFileDownloadDialog call to main thread." << endl;
        [self performSelectorOnMainThread:@selector(ShowFileDownloadDialog) withObject:nil waitUntilDone:YES];
    }
}
@end 
#endif

Я вызываю это из кода, который у меня есть в различных потоках, обрабатывающих входящие сетевые сообщения:

cout << "Creating CocoaInterface." << endl;
CocoaInterface* interface = [[CocoaInterface alloc] init];
cout << "Calling CocoaInterface::ShowFileDownloadDialog." << endl;
[interface ShowFileDownloadDialog];

Это зависает при попытке выполнить селектор - как будто он никогда не сможет найти основной поток. След в GDB показывает, что я вечно жду семафора.

Когда я раскомментирую вызов NSRunAlertPanel перед вызовом PerformSelectorOnMainThread, я получаю белый блок в форме диалога, но он не полностью рисует или обрабатывает какие-либо сообщения, предположительно потому, что он не находится в основном потоке графического интерфейса.

Кажется, у меня нет надлежащего потока графического интерфейса или я просто не могу добраться до него оттуда, где я нахожусь. Я подозреваю, что я что-то пропустил в инициализации. Какие-либо предложения?


person Jason Champion    schedule 07.12.2010    source источник


Ответы (2)


Вместо того, чтобы явно создавать объект NSApplication, вы должны вызвать NSApplicationLoad(), который обработает создание экземпляра и создаст для вас цикл обработки событий.

Вы также можете использовать функцию NSLog(@"Some string") вместо всех этих cout, если хотите.

person Rob Keniger    schedule 08.12.2010
comment
Спасибо, но кажется, что NSApplicationLoad() предназначен для приложений Carbon, и в этом конкретном приложении нет Carbon. - person Jason Champion; 10.12.2010

Оказывается, мне нужно было сочетание этих двух вещей:

[NSApplication sharedApplication];
[NSApp run];

Я был избалован другими GUI API, такими как GTK и wxWidgets, так что вызов

[NSApp terminate: nil];

застал меня врасплох, неожиданно уничтожив все приложение с помощью вызова exit(0), а остальная часть main() никогда не выполняется, но это, по-видимому, предполагаемое поведение и тема для другого дня.

person Jason Champion    schedule 10.12.2010
comment
Да, это предполагаемое поведение. Где-то в документации написано. - person Yuji; 10.12.2010