开篇
iOS面试中,runLoop,runtime,内存管理,性能优化等更底层更的问题越来越受面试官的青睐,这确实是考察一个程序员知识深度和自主钻研能力的基本手段。虽然大多数程序员在开发过程中,这些知识点用的并不多,但是掌握这些知识,会帮助你写出更优秀的代码,避免一些“莫名其妙”的坑。想成为一名真正优秀的工程师,确实应该在相应的领域不断深挖,才能到达大多数到不了的高度。
此篇讲讲面试中runLoop相关的一些问题,由问题引出背后的原理。
1. 在主线程中用NSTime设定一个定时器,滑动scrollView,会对定时器造成什么影响,为什么?
看起来是个NSTimer的问题,实际上关系到了runLoop。
其实NSTimer定时器的触发正是基于RunLoop运行的,所以使用NSTimer之前必须注册到RunLoop。
而一个runLoop每次只能在一种模式下运行,这就引出了Runloop Mode:
Runloop Mode
系统默认提供的Run Loop Modes有:
1.kCFRunLoopDefaultMode(NSDefaultRunLoopMode),系统默认的模式
2.UITrackingRunLoopMode 滑动UIScrollView时,会切换到此mode
特别注意,开发中还会遇到这种模式:kCFRunLoopCommonModes(NSRunLoopCommonModes)
kCFRunLoopCommonModes其实并不是一种具体的mode,而是一种mode的组合,在iOS系统中默认包含了
NSDefaultRunLoopMode和 UITrackingRunLoopMode
滑动UIScrollView,主线程就切换Runloop到了UITrackingRunLoopMode,不再接受其他事件操作,这是为了保证滑动的流畅性。那么这个时候,NSTimer就失效了。
为了避免这种情况,有两种解决办法:
- 把定时器添加到当前线程消息循环中 并指定消息循环的模式为NSRunLoopCommonModes;
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:selfselector:@selector(demo) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes]; 把NSTimer放到子线程中,在主线程中更新UI;
2. 在ViewDidLoad中开4个定时器NSTimer,四个定时器中操作同一个可变数组,线程安全吗?
在ViewDidLoad中开4个定时器NSTimer,那么这四个timer就是在同一个runLoop中,即APP的主rumLoop中,所以是在同一个线程中操作的可变数组(线程和Runloop二者一一对应),所以是线程安全的。
3. 如何自定义一套iOS系统中的通知中心(NSNotificationCenter)
说实话,这个问题有点扯淡,我相信开发中谁也不会去自定义一套通知中心。但是这个问题是考察runLoop的底层原理的。这是可以用runLoop实现的。
大家都知道runLoop实质是一个while循环,它静态时一直处于“等待-处理”的循环之中,即休眠状态,当监听到外部消息(source)时,就会唤醒,去处理相应的事件。看看官方给的runLoop结构示意图:
右边的source包含了Timer Sources和InputSources,其中InputSources包含了自定义Source。所以可以试着用这个自定义Source。
还有runLoop中的Observer(监听器)和Call out(在开发过程中几乎所有的操作都是通过Call out进行回调的)。
可以看出,runLoop中的source、Observer和Call out,可以组成通知中心的要素。
想要系统了解RunLoop原理,请参考下面这篇高质量博客:https://www.cnblogs.com/kenshincui/p/6823841.html