Я знаю, что я не первый, кто пытается использовать Cocoa в OSX вместе с существующим основным циклом c/С++, но мне не очень нравятся решения, с которыми я сталкивался до сих пор, поэтому я придумал другую идею, которую я хотел бы обсудить. Самый распространенный способ, который я нашел (в glut, glfw, SDL, а также QT, я думаю), - использовать опрос для замены метода запуска NSApplications и самостоятельно обрабатывать события:
nextEventMatchingMask:untilDate:inMode:dequeue:
Это имеет большой недостаток: CPU никогда не бывает бездействующим, так как вы должны все время опросить, чтобы проверить, есть ли какие-либо новые события, кроме того, это не единственное, что происходит внутри функции NSApplications, поэтому оно может сломать некоторые если вы используете эту замену.
Так что я хотел бы сделать, чтобы сохранить Cocoa runLoop неповрежденным. Представьте, что у вас есть свои собственные методы таймера, реализованные в С++, которые обычно управляются и запускаются внутри вашего основного цикла (в качестве примера это небольшая часть). Моя идея состояла бы в том, чтобы переместить все мои фрагменты цикла во вторичный поток (поскольку запуск NSApplication нужно вызывать из основного потока, насколько я знаю), а затем отправлять пользовательские события в мою производную версию NSApplication, которая соответствующим образом обрабатывает их внутри sendEvent: метод. Например, если мои таймеры были измерены в моем цикле цикла С++, я бы опубликовал пользовательское событие в NSApplication, которое, в свою очередь, запускает функцию loopFunc() моего приложения (также находящуюся в mainthread), которая соответствующим образом отправляет события по моей цепочке событий С++, Итак, в первую очередь, как вы думаете, это было бы хорошим решением? Если да, как бы вы реализовали это в cocoa, я нашел этот метод только в NSEvent Reference для публикации пользовательских событий NSApplicationDefined:
otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:
а затем используйте что-то вроде:
[NSApp postEvent:atStart:]
чтобы уведомить NSApplication.
Я предпочел бы разместить событие без какой-либо информации о окне (в otherEventWithType), могу ли я просто игнорировать эту часть?
Тогда я мог бы переписать функцию sendAvent NSApplications, подобную этой:
- (void)sendEvent:(NSEvent *)event
{
//this is my custom event that simply tells NSApplication
//that my app needs an update
if( [event type] == NSApplicationDefined)
{
myCppAppPtr->loopFunc(); //only iterates once
}
//transform cocoa events into my own input events
else if( [event type] == NSLeftMouseDown)
{
...
myCppAppPtr->loopFunc(); //also run the loopFunc to propagate input events
}
...
//dont break the cocoa event chain
[super sendEvent:event];
}
Извините за длинный пост, но это немного беспокоило меня, так как я действительно недоволен тем, что я нашел по этому вопросу до сих пор. Является ли это тем, как я опубликовал и проверил бы пользовательское событие внутри NSApplication, и считаете ли вы, что это допустимый подход для интеграции Cocoa в существующую runloop без опроса?