IOS 如何优雅且实用地阻塞(后续)程序
- 前言
- NSTimer(推荐!)
- NSThread
- GCD
- 结语
前言
有时需要延迟执行一些程序(如:跳转),首先想到的肯定是直接阻塞主进程(线程),使用 sleep:(NSTimeInterval)ti
即可。
但这种方式会使主线程的动画(animation)也被阻塞,因此并不适用于所有情况!
下面就介绍几种可以延迟执行程序,并且不会阻塞主进程的解决方案。
但由于 IOS 必须要在主线程操作 UI,所以涉及 UI 操作(包括跳转)不应该使用线程方法!
实验环境:XCode 10.1
语言:Objective-C
NSTimer(推荐!)
基于 NSTimer 设置一定时间间隔后,再执行函数,来实现“阻塞(后续)程序”的效果:
[NSTimer scheduledTimerWithTimeInterval:2 target:self
selector:@selector(stopLoading) userInfo:nil repeats:NO];
- 您可以使用上面这条语句在程序中间创建一个定时器。
- 该语句的含义为在 2s 之后,调用
@selector
中的函数。 - 也就是说您需要想办法将想要延迟执行的程序,放在一个函数中,然后依赖定时器在一段时间后再调用函数,执行需要延迟执行的程序。
- 注意:上面的语句会返回一个 NSTimer 对象,在这里我们不需要用到这个对象,因此代码中没有对返回值进行“接收”。
由于 NSTimer 没有阻塞主进程,只是设置了一个定时器,在一定时间间隔后通知主线程去调用一个预设的函数(@selector),因此不会对主进程的程序执行造成影响。
NSThread
使用 NSTimer 是一个非常取巧的办法,我们其实也可以自己创建新线程来实现上面的效果。
NSThread 是 Apple 提供的针对 PThread 封装的 OC 对象。只暴露了 PThread(底层 API,就像 axios 之于 fetch) 的部分能力,简单易用!
NSThread 提供了一个 + (void)sleepForTimeInterval:(NSTimeInterval)ti;
静态方法,可以对当前线程进行阻塞:
// 创建并开启子线程
NSThread *thread = [[NSThread alloc] initWithTarget:self
selector:@selector(jump)
object:nil];
[thread start];
- (void)jump{
[NSThread sleepForTimeInterval:2];
// sleep(2);
// 需要延迟执行的代码
...
}
在子线程中使用 sleepForTimeInterval
静态方法,或者 sleep
对其进行阻塞,然后执行需要延迟执行的程序都可以!
但是需要注意,因为 UIKit 不是线程安全的(也就是说允许出现多个线程同时操作 UI 的情况),所以如果涉及 UI 的操作,就不应该使用线程方法,而应该使用 NSTimer 进行延迟执行。否则 XCode 会报错(但程序不一定会终止)。
GCD
Grand Central Dispatch(GCD) 是 Apple 开发的一个多核编程解决方法,是在线程池模式的基础上执行的并发任务。
我们可以使用 dispatch_queue_create("serial-queue", NULL)
创建一个串行队列,然后使用 dispatch_after
添加异步任务,并指定启动时间,实现异步、延迟执行程序。
GCD 给队列添加任务是完全基于 Block 的(无法使用函数指针)。下面是一个小小的示例:
dispatch_queue_t queue = dispatch_queue_create("serial-queue", NULL);
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)),
queue,
^{ // 传入一个 block
// 需要延迟执行的代码
...
}
);
GCD 同样是基于线程的方法,只是使用了一个封装的线程池,涉及修改 UI 的操作时,也会报错,并且 GCD 会自动阻止相关代码的执行。
结语
本文提供的三个延迟执行程序的代码均经过了测试,但是只推荐大家使用 NSTimer。
如有差错,敬请指正。