# 1. 猜想runloop内部是如何实现的?
从字面意思看:运行循环、跑圈;
本质:
内部就是do-while
循环,在这个循环内部不断地处理各种事件(任务),比如:Source
、Timer
、Observer
;
每条线程都有唯一一个RunLoop对象与之对应,主线程的RunLoop默认已经启动,子线程的RunLoop需要手动启动; 每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode,如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入,这样做主要是为了隔离不同Mode中的Source、Timer、Observer,让其互不影响;
附上RunLoop的运行图 :
# 2. 苹果是如何实现autoreleasepool的?
autoreleasepool
以一个队列数组的形式实现,主要通过下列三个函数完成.
objc_autoreleasepoolPush
objc_autoreleasepoolPop
objc_aurorelease
看函数名就可以知道,对autorelease分别执行push,和pop操作。销毁对象时执行release操作
# 3. GCD的队列(dispatch_queue_t)分哪两种类型?背后的线程模型是什么样的?
串行队列、并行队列
dispatch_global_queue();
是全局并发队列
dispatch_main_queue();
是一种特殊串行队列
背后的线程模型:
自定义队列dispatch_queue_t queue;
可以自定义是并行:DISPATCH_QUEUE_CONCURRENT
或者 串行 DISPATCH_QUEUE_SERIAL
# 4. 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
必须是并发队列才起作用
需求分析: 首先,分别异步执行2个耗时的操作, 其次,等2个异步操作都执行完毕后,再回到主线程执行一些操作
使用队列组实现上面的需求:
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 往队列组中添加耗时操作
dispatch_group_async(group, queue, ^{
// 执行耗时的异步操作1
});
// 往队列组中添加耗时操作
dispatch_group_async(group, queue, ^{
// 执行耗时的异步操作2
});
// 当并发队列组中的任务执行完毕后才会执行这里的代码
dispatch_group_notify(group, queue, ^{
// 如果这里还有基于上面两个任务的结果继续执行一些代码,建议还是放到子线程中,等代码执行完毕后在回到主线程
// 回到主线程
dispatch_async(group, dispatch_get_main_queue(), ^{
// 执行相关代码...
});
});
# 5. 以+scheduledTimerWithTimeInterval...的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?
这里强调一点:
在主线程中以+scheduledTimerWithTimeInterval...
的方式触发的timer默认是运行在NSDefaultRunLoopMode
模式下的,当滑动页面上的列表时,进入了UITrackingRunLoopMode
模式,这时候timer就会停止
可以修改timer的运行模式为NSRunLoopCommonModes
,这样定时器就可以一直运行了
补充:
- 在子线程中通过
scheduledTimerWithTimeInterval:...
方法来构建NSTimer - 方法内部已经创建
NSTimer
对象,并加入到RunLoop中,运行模式为NSDefaultRunLoopMode
- 由于Mode有timer对象,所以RunLoop就开始监听定时器事件了,从而开始进入运行循环
- 这个方法仅仅是创建RunLoop对象,并不会主动启动RunLoop,需要再调用run方法来启动
- 如果在主线程中通过
scheduledTimerWithTimeInterval:...
法来构建NSTimer,就不需要主动启动RunLoop对象,因为主线程的RunLoop对象在程序运行起来就已经被启动了
// userInfo参数:用来给NSTimer的userInfo属性赋值,userInfo是只读的,只能在构建NSTimer对象时赋值
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(run:) userInfo:@"ya了个hoo" repeats:YES];
// scheduledTimer...方法创建出来NSTimer虽然已经指定了默认模式,但是【允许你修改模式】
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 【仅在子线程】需要手动启动RunLoop对象,进入运行循环
[[NSRunLoop currentRunLoop] run];