До появления вот этой темы на РСДНе я как-то не предавал особого значения таймерам в Mac OS X. Ну есть они и есть, как будет нужно так разберусь. Но как оказалось, стандартных POSIX вызовов, таких как timer_create/timer_delete у нас нет, а то что есть не всегда подходит.
Хорошенько поковырявшись в документации я пришел к следующему выводу. Всего доступны 3 способа работы с таймерами, дающие приблизительно одинаковый эффект:
- NSTimer из Foundation;
- RunLoop из CoreFoundation;
- Таймеры из Mach. Хотя у меня данный пункт вызвал некоторые трудности.
Так что по порядку, с краткими иллюстрациями.
NSTimer из Foundation
Самый простой и наиболее кошерный способ. Подходит для всех, кто не боится использовать Objective-C. Документация к NSTimerподробна и содержит кучу примеров.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:YES]; NSRunLoop *loop = [NSRunLoop currentRunLoop];[loop addTimer:timer forMode:NSDefaultRunLoopMode]; time_t startTime, endTime;time( &startTime ); while (count <= 10 ) [loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; time( &endTime ); printf( "Time:t%dnCount:t%dn", (int)(endTime - startTime), count );
Тут, по моему, даже писать особо не о чем (да и лень мне )
RunLoop из CoreFoundation
По большому счету, это тоже самое что и использование NSTimer, только из Си. Наиболее интересная документация называется CFRunLoopTimer Reference, а используется вся эта радость приблизительно так:
int32_t val = 0;CFRunLoopTimerContext context = {};context.info = &val; CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 0.1, 0, 0, RunLoopCallBack, &context); if( timer ) CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); time_t starttime, endtime; time( &starttime ); while (val <= 10 ) CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, false time( &endtime ); printf( "Time:t%dnCount:t%dn", (int)(endtime - starttime), val );
Я конечно понимаю, что это все индивидуально, но лично мне вариант с использованием CFRunLoopTimer нравится больше. Лаконичнее и проще.
Mach таймеры
А вот тут я несколько запутался. Толи я неправильно использовал clock_alarm, толи еще что-то, но если убрать закомментированную проверку в примере ниже, то появится сообщение об ошибке. Тем не менее, если ошибку игнорировать все вроде даже работает.
current_task = mach_task_self(); kr = host_get_clock_service( mach_host_self(), SYSTEM_CLOCK, &clk_server );CHK_KR_ERROR(kr, "host_get_clock_service"); mach_timespec_t alarm_time;alarm_time.tv_sec = 0;alarm_time.tv_nsec = 50000000;clock_reply_t alarm_port; kr = mach_port_allocate( current_task, MACH_PORT_RIGHT_RECEIVE, &alarm_port );CHK_KR_ERROR(kr, "mach_port_allocate"); time( &starttime );int val = 0;while( 10 >= val ){ kr = clock_alarm( clk_server, TIME_RELATIVE, alarm_time, alarm_port ); CHK_KR_ERROR(kr, "clock_alarm"); kr = mach_msg( &header, MACH_RCV_MSG, 0, header.msgh_size, alarm_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL );// CHK_KR_ERROR(kr, "mach_msg"); ++val;}time( &endtime ); printf( "Time:t%dnCount:t%dn", (int)(endtime - starttime), val );
Код целиком можно скачать тут.