2010-07-15 5 views
2

В моем приложении я добавьте CFMachPortRef (через CFMachPortCreateRunLoopSource) до нитей CFRunLoopНОД и RunLoops

Сейчас я задавал себе, это может быть сделано с помощью НОД? Скажем, вместо нерест моего NSThread и добавьте созданный CFRunLoopSourceRef его запуск цикла через CFRunLoopAddSource, добавьте порт события для runloop депеши в?

Я думаю, что это скорее всего не сработает из-за внутренней работы GCD, но я действительно не знаю.

Update


Я получил это до сих пор, однако ни функцию обратного вызова для крана событий, ни блок dispatch_source_event_handler называется. Есть идеи?

CFMachPortRef port = CGEventTapCreate(kCGSessionEventTap, 
             kCGHeadInsertEventTap, 
             opts, 
             desc_.eventMask, 
             _CGEventCallback, 
             self); 

// create dispatch source 
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, 
                CFMachPortGetPort(port), 
                0, 
                dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 

// set event handler 
dispatch_source_set_event_handler(source, ^{ 
    printf("handle me!\n"); 
}); 

dispatch_resume(source); 
+0

«CFMachPort» объединяет порт Mach с обратным вызовом. Если вы используете GCD только для контроля порта Mach, вы игнорируете обратный вызов. В случае касания события обратный вызов является внутренним для Core Graphics и, по-видимому, делает важные вещи (например, получение сообщения Mach из порта, его декодирование и вызов * вашего * обратного вызова). –

ответ

2

Фактически вы можете использовать GCD для контроля порта Mach, используя функцию dispatch_source_create(). Код будет выглядеть примерно так:

mach_port_t myPort; //assume you have this already 
dispatch_source_t portSource; 

portSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, myPort, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT)); 
dispatch_source_set_event_handler(portSource, ^(void) { //code for handling incoming message here }); 

dispatch_resume(portSource); 

Всякий раз, когда сообщение приходит в порт, блок вы передаете в качестве обработчика событий должен вызываться, и вы можете обработать сообщение там. Этот пример просто использует глобальную очередь, предоставленную GCD для обработки сообщения, но вы можете создать собственную очередь, если хотите.

+0

не работает (по крайней мере для моего случая): смотреть * обновление * раздел выше. –

+0

, если вы разместите сообщение «не будет работать с этим путем с помощью событий», я могу принять ваш ответ :) –

+0

Я не совсем уверен, почему этот код не работает, я на самом деле не использовал источники событий GCD с (я использовал другие типы источников GCD), поэтому я не уверен, есть ли ограничение с портами, созданными для событийных ответвлений. Вы пробовали способ CFRunLoop делать что-то, только чтобы убедиться, что по крайней мере крана создается правильно и работает в этом контексте? –

0

Чтобы запланировать обратные вызовы из порта уведомлений в очереди GCD, вы можете использовать IONotificationPortSetDispatchQueue вместо CFRunLoopAddSource с Runloop.

Пример:

IOServiceOpen(driver, mach_task_self(), 0, &connection); 

notifyPort = IONotificationPortCreate(kIOMasterPortDefault); 

IOServiceAddInterestNotification(
    notifyPort, 
    driver, 
    kIOGeneralInterest, 
    myCallback, 
    NULL, //refcon 
    &notificationObject 
); 

// Instead of this: 
// CFRunLoopAddSource(CFRunLoopGetCurrent(), 
//     IONotificationPortGetRunLoopSource(notifyPort), 
//     kCFRunLoopDefaultMode); 
// do this: 
IONotificationPortSetDispatchQueue(notifyPort, myQueue); 

Это заставит myCallback() обработчик называться по очереди GCD myQueue.