定时操作对于开发人员来说有着广泛的应用场景;对于iOS开发,实现定时操作的手法也有多种,这里我们简单的进行比较和分析。
1. NSTimer 简单易上手,最高级的api,调用也比较方便。(精度也最低)
但:NSTimer在不做任何额外设置的情况下只能在主线程使用,且会受到其他任务的干扰(主线程runloop执行其他任务,nstimer就不能及时触发);
可以设置NSRunLoopCommonModes来对其加以改善,这个时候主线程的UI操作已经不会阻塞它的触发了。
performselector after delay 可以认为是1的变种,精度和NSTimer相同。
2.使用 gcd的api, dispatch_after来进行定时操作。
该api虽然属于gcd的操作序列,但调用也比较方便,同时不受主线程UI操作的干扰,精度也尚可;不失为NSTimer的一个高级替代品。
dispatch_source_set_timer 是一个更复杂一些的定时api方法,提供了更多的参数和设置,可以提供相对dispatch_after来说更好的精度(推测
dispatch_after
可能使用了默认的精度,误差在几十毫秒左右)。
3.要获得更好的精度,需要使用更底层的api实现,大概可以精确到毫秒级别。
首先你要搞一个更牛逼的实时线程:
#include <mach/mach.h> |
#include <mach/mach_time.h> |
#include <pthread.h> |
void move_pthread_to_realtime_scheduling_class(pthread_t pthread) |
{ |
mach_timebase_info_data_t timebase_info; |
mach_timebase_info(&timebase_info); |
const uint64_t NANOS_PER_MSEC = 1000000ULL; |
double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC; |
thread_time_constraint_policy_data_t policy; |
policy.period = 0; |
policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work |
policy.constraint = (uint32_t)(10 * clock2abs); |
policy.preemptible = FALSE; |
int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()), |
THREAD_TIME_CONSTRAINT_POLICY, |
(thread_policy_t)&policy, |
THREAD_TIME_CONSTRAINT_POLICY_COUNT); |
if (kr != KERN_SUCCESS) { |
mach_error("thread_policy_set:", kr); |
exit(1); |
} |
} |
然后你需要相对应的定时api:
#include <mach/mach.h> |
#include <mach/mach_time.h> |
static const uint64_t NANOS_PER_USEC = 1000ULL; |
static const uint64_t NANOS_PER_MILLISEC = 1000ULL * NANOS_PER_USEC; |
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MILLISEC; |
static mach_timebase_info_data_t timebase_info; |
static uint64_t abs_to_nanos(uint64_t abs) { |
return abs * timebase_info.numer / timebase_info.denom; |
} |
static uint64_t nanos_to_abs(uint64_t nanos) { |
return nanos * timebase_info.denom / timebase_info.numer; |
} |
void example_mach_wait_until(int argc, const char * argv[]) |
{ |
mach_timebase_info(&timebase_info); |
uint64_t time_to_wait = nanos_to_abs(10ULL * NANOS_PER_SEC); |
uint64_t now = mach_absolute_time(); |
mach_wait_until(now + time_to_wait); |
} |
参考文档:https://developer.apple.com/library/content/technotes/tn2169/_index.html