iOS程序启动与运转-Runloop
2016-03-10 18:55
399 查看
学习iOS开发一般都是从UI开始的,从只知道从IB拖控件,到知道怎么在方法里写代码,然后会显示什么样的视图,产生什么样的事件,等等。其实程序从启动开始,一直都是按照苹果封装好的代码运行着,暴露的一些属性和方法作为接口,是让我们在给定的方法里写代码实现自定义功能,做出各种各样的应用。这些方法的调用顺序最为关键,熟悉了程序运转和方法调用的顺序,才可以更好地操控程序和代码,尽量避免Xcode不报错又实现不了功能的BUG。从Xcode的线程函数调用栈可以看到一些方法调用顺序。
0从程序启动开始到view显示:
start->(加载framework,动态静态链接库,启动图片,Info.plist,pch等)->main函数->UIApplicationMain函数:
0从程序启动开始到view显示:
start->(加载framework,动态静态链接库,启动图片,Info.plist,pch等)->main函数->UIApplicationMain函数:
UIApplication:
通过window管理视图;
发送Runloop封装好的control消息给target;
处理URL,应用图标警告,联网状态,状态栏,远程事件等。
AppDelegate:
管理UIApplication生命周期和应用的五种状态(notRunning/inactive/active/background/suspend)。
KeyWindow:
显示view;
管理rootViewcontroller生命周期;
发送UIApplication传来的事件消息给view。
rootViewController:
管理view(view生命周期;view的数据源/代理;view与superView之间事件响应nextResponder的“备胎”);
界面跳转与传值;
状态栏,屏幕旋转。
view:
通过作为CALayer的代理,管理layer的渲染(顺序大概是先更新约束,再layout再display)和动画(默认layer的属性可动画,view默认禁止,在UIView的block分类方法里才打开动画)。layer是RGBA纹理,通过和mask位图(含alpha属性)关联将合成后的layer纹理填充在像素点内,GPU每1/60秒将计算出的纹理display在像素点中。
布局子控件(屏幕旋转或者子视图布局变动时,view会重新布局)。
事件响应:event和guesture。
插播控制器生命周期
runloop:
(要让马儿跑)通过do-while死循环让程序持续运行:接收用户输入,调度处理事件时间。
(要让马儿少吃草)通过mach_msg()让runloop没事时进入trap状态,节省CPU资源。
关于程序启动原理以及各个控件的资料,已经有太多资料介绍,平时我们也经常接触经常用到,但关于Runloop的资料,官方文档总是太过简练,网上资源说法也不太统一,只能从CFRunLoopRef开源代码着手,试着学习总结下。(NSRunloop是对CFRunloopRef的面向对象封装,但是不是线程安全)。
1Runloop
1、与线程和自动释放池相关:
2、CFRunLoopRef构造:数据结构;创建与退出;mode切换和item依赖;Runloop启动
-CFRunLoopModeRef:数据结构(与CFRunLoopRef放一起了);创建;类型;
modeItems:-CFRunLoopSourceRef:数据结构(source0/source1);
-source0:
-source1:
-CFRunLoopTimerRef:数据结构;创建与生效;相关类型(GCD的timer与CADisplayLink)
-CFRunLoopObserverRef:数据结构;创建与添加;监听的状态;
3、Runloop内部逻辑:关键在两个判断点(是否睡觉,是否退出)
-代码实现:
-函数作用栈显示:
4、Runloop本质:machport和mach_msg()。
5、如何处理事件:
-界面刷新:
-手势识别:
-GCD任务:
-timer:(与CADisplayLink)
-网络请求:
6、应用:
-滑动与图片刷新;
-常驻子线程,保持子线程一直处理事件
-滑动与图片刷新;
Runloop
1、与线程和自动释放池相关:
Runloop的寄生于线程:一个线程只能有唯一对应的runloop;但这个根runloop里可以嵌套子runloops;
自动释放池寄生于Runloop:程序启动后,主线程注册了两个Observer监听runloop的进出与睡觉。一个最高优先级OB监测Entry状态;一个最低优先级OB监听BeforeWaiting状态和Exit状态。
线程(创建)-->runloop将进入-->最高优先级OB创建释放池-->runloop将睡-->最低优先级OB销毁旧池创建新池-->runloop将退出-->最低优先级OB销毁新池-->线程(销毁)
2、CFRunLoopRef构造:
数据结构:
创建与退出:mode切换和item依赖
a主线程的runloop自动创建,子线程的runloop默认不创建(在子线程中调用NSRunLoop*runloop=[NSRunLoopcurrentRunLoop];
获取RunLoop对象的时候,就会创建RunLoop);
brunloop退出的条件:app退出;线程关闭;设置最大时间到期;modeItem为空;
c同一时间一个runloop只能在一个mode,切换mode只能退出runloop,再重进指定mode(隔离modeItems使之互不干扰);
d一个item可以加到不同mode;一个mode被标记到commonModes里(这样runloop不用切换mode)。
启动Runloop:
CFRunLoopModeRef:
数据结构(见上);
创建添加:runloop自动创建对应的mode;mode只能添加不能删除
类型:
1.kCFRunLoopDefaultMode:默认mode,通常主线程在这个Mode下运行。
2.UITrackingRunLoopMode:追踪mode,保证Scrollview滑动顺畅不受其他mode影响。
3.UIInitializationRunLoopMode:启动程序后的过渡mode,启动完成后就不再使用。
4:GSEventReceiveRunLoopMode:Graphic相关事件的mode,通常用不到。
5:kCFRunLoopCommonModes:占位mode,作为标记DefaultMode和CommonMode用。
modeItems:
A--CFRunLoopSourceRef:事件来源
按照官方文档CFRunLoopSourceRef为3类,但数据结构只有两类(???)
Port-BasedSources:与内核端口相关
CustomInputSources:与自定义source相关
CocoaPerformSelectorSources:与PerformSEL方法相关)
数据结构(source0/source1);