今天博主有一个RunLoop的需求,遇到了一些困难点,在此和大家分享,希望能够共同进步.

RunLoop是什么?

从字面上理解,Runloop指的就是运行循环,iOS中,只要程序启动, 就会创建Runloop,用来处理各种事件(比如定时器事件, 触摸事件等).

它的主要作用有以下几个:

1.保持程序的运行:如果没有它, 程序一启动就over了;

2.事件的处理: 包括按钮点击事件, 屏幕的点击事件等;

3.定时器处理: NSTimer的处理;

4.节约CPU, 提高性能:有任务的时候干活,没有任务时候休息.

在iOS中, 可以通过两套API来访问Runloop:

1.Foundation框架: OC中的框架, 直接访问NSRunLoop对象.

2.Core Foundation框架: c语言的框架, 通过CFRunLoopRef访问.

实际上, NSRunLoop和CFRunLoopRef是同一个对象, 只不过通过不同的API来访问的,NSRunLoop是对CFRunLoopRef的封装.

OC中, 使用下面代码就可以获得Runloop对象:

// Foundation

[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象

[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象

// Core Foundation

CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象

CFRunLoopGetMain(); // 获得主线程的RunLoop对象

Nslog打印Runloop对象, 里面的内容如下:(由于内容比较多, 只将重点内容列出)

 // runloop对象<CFRunLoop 0x7fb13172abc0 [0x10a5aa180]>{wakeup port = 0x1003, stopped = false, ignoreWakeUps = true, // 当前模式 current mode = UIInitializationRunLoopMode, common modes = <CFBasicHash 0x7fb13172ac80 // common modes标记了哪两个模式(后面会讲为啥是标记?) 0 : <CFString 0x10b27ce50 [0x10a5aa180]>{contents = "UITrackingRunLoopMode"} 2 : <CFString 0x10a586080 [0x10a5aa180]>{contents = "kCFRunLoopDefaultMode"} } // source: 源 6 : <CFRunLoopSource 0x7fb131415300 [0x10a5aa180]> // observers: 观察者 observers = <CFArray 0x7fb13141d300 [0x10a5aa180]> // timer: 定时器 timers = (null), // 两种不同的模式 3 : <CFRunLoopMode 0x7fb13172dbb0 [0x10a5aa180]>{name = GSEventReceiveRunLoopMode, port set = 0x2003, timer port = 0x2103, sources0 = <CFBasicHash 0x7fb13172d260 [0x10a5aa180]>{type = mutable set, count = 1, entries => 0 : <CFRunLoopSource 0x7fb13172da30 [0x10a5aa180]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x10d8236c8)}} }

要想知道上面内容是什么意思, 先看下面的内容:

Core Foundation中关于RunLoop的5个类
1.CFRunLoopRef
2.CFRunLoopModeRef 3.CFRunLoopSourceRef 4.CFRunLoopTimerRef 5.CFRunLoopObserverRef 可以这理解为, 一个Runloop对象里面, 必不可少的是CFRunLoopModeRef, Mode里面可以包含timer/source/oberver(只有包含了其中一个, Runloop才能在启动后保证不死)

层级结构如下图:

接下来, 对里面的内容说明一下:

一.CFRunLoopModeRef:代表RunLoop的运行模式1.一个RunLoop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer2.每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作CurrentMode3.这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响
系统默认注册了5个Mode: 1.kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行 2.UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响 3.UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用 4.GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到 5.kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode, 被标记为kCFRunLoopCommonModes格式的都可以成为commonMode, 其中包含1.2两种模式. 二.CFRunLoopSourceRef:是事件源(输入源) 现在主要分为两种: Source0:非基于Port的 Source1:基于Port的(如GCD底层实现也是通过Port的, 主要用于线程之间的通信) 三.CFRunLoopTimerRef:是基于时间的触发器, 基本上说的就是NSTimer 四.CFRunLoopObserverRef:观察者, 可以用来监听Runloop的状态, 下面列出了Runloop的状态 typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { kCFRunLoopEntry = (1UL << 0), // 即将进入 kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理timer kCFRunLoopBeforeSources = (1UL << 2), // 即将处理事件源 kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠 kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒 kCFRunLoopExit = (1UL << 7), // 即将退出Runloop };

下面图片描述了Runloop的运行和状态:

Runloop的寄生于线程:一个线程只能有唯一对应的runloop;但这个根runloop里可以嵌套子runloops;
自动释放池寄生于Runloop:程序启动后,主线程注册了两个Observer监听runloop的进出与睡觉。一个最高优先级OB监测Entry状态;一个最低优先级OB监听BeforeWaiting状态和Exit状态。
线程(创建)-->runloop将进入-->最高优先级OB创建释放池-->runloop将睡-->最低优先级OB销毁旧池创建新池-->runloop将退出-->最低优先级OB销毁新池-->线程(销毁)

Mach是XNU的内核,进程、线程和虚拟内存等对象通过端口发消息进行通信,Runloop通过mach_msg()函数发送消息,如果没有port 消息,内核会将线程置于等待状态 mach_msg_trap() 。如果有消息,判断消息类型处理事件,并通过modeItem的callback回调。

Runloop有两个关键判断点,一个是通过msg决定Runloop是否等待,一个是通过判断退出条件来决定Runloop是否循环。

应用1:滑动与图片刷新:

当tableview的cell上有需要从网络获取的图片的时候,滚动tableView,异步线程会去加载图片,加载完成后主线程就会设置cell的图片,但是会造成卡顿。可以让设置图片的任务在CFRunLoopDefaultMode下进行,当滚动tableView的时候,RunLoop是在 UITrackingRunLoopMode 下进行,不去设置图片,而是当停止的时候,再去设置图片。

- (void)viewDidLoad { 

[super viewDidLoad];  // 只在NSDefaultRunLoopMode下执行(刷新图片) 

[self.myImageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@""] afterDelay:ti inModes:@[NSDefaultRunLoopMode]];  

 }

应用2:常驻子线程,保持子线程一直处理事件
为了保证线程长期运转,可以在子线程中加入RunLoop,并且给Runloop设置item,防止Runloop自动退出。

+ (void)networkRequestThreadEntryPoint:(id)__unused object {@autoreleasepool {[[NSThread currentThread] setName:@"AFNetworking"]; NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; [runLoop run]; } } + (NSThread *)networkRequestThread { static NSThread *_networkRequestThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; [_networkRequestThread start]; }); return _networkRequestThread; } - (void)start { [self.lock lock]; if ([self isCancelled]) { [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; } else if ([self isReady]) { self.state = AFOperationExecutingState; [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; } [self.lock unlock]; }

http://www.cnblogs.com/66it/p/4719701.html?utm_source=tuicoolhttp://blog.ibireme.com/2015/05/18/runloop/

转载于:https://www.cnblogs.com/Twisted-Fate/p/4831510.html

iOS开发日记24-详解RunLoop相关推荐

  1. iOS开发证件要点详解

    iOS开发证书要点详解 引言 关于开发证书配置(Certificates&Identifiers&Provisioning Profiles),相信做iOS开发的同学没少被折腾.对于一 ...

  2. IOS开发-GitHub使用详解

    1.GitHub是什么? GitHub这个名词既可以是那个流行的代码分享和协作网站 https://github.com/,也可以是指Git客户端工具(与其他的Git客户端工具如GitEye类似,只不 ...

  3. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html IT168 技术文档]在开始步入Lin ...

  4. iOS里面MVC模式详解

    iOS里面MVC模式详解 MVC是IOS里面也是很多程序设计里面的一种设计模式,M是model,V是view,C是controller.MVC模式在ios开发里面可谓是用得淋漓尽致. 以下是对斯坦福大 ...

  5. iOS APP上架流程详解

    iOS APP上架流程详解 青葱烈马 2016.04.28  前言:作为一名 iOS 开发工程师, APP 的上架是必备技能. iOS 上架的流程主要可以简单总结为: 一个包,两个网址,三个证书, 一 ...

  6. iOS中ImageIO框架详解与应用分析

    2019独角兽企业重金招聘Python工程师标准>>> iOS中ImageIO框架详解与应用分析 一.引言 ImageIO框架提供了读取与写入图片数据的基本方法,使用它可以直接获取到 ...

  7. STM32开发 -- 低功耗模式详解

    很多单片机都有低功耗模式,STM32 也不例外.当 CPU 不需继续运行时,可以利用多个低功耗模式来节省功耗. 这部分不是我负责,但是也是有必要看一下的. 参看: STM32F1开发指南-库函数版本_ ...

  8. [置顶] iOS中 支付宝钱包详解/第三方支付

    [置顶] iOS中 支付宝钱包详解/第三方支付 韩俊强的博客 每日更新关注:http://weibo.com/hanjunqiang  新浪微博! 一.在app中成功完成支付宝支付的过程 1.申请支付 ...

  9. NRF52x开发环境搭建详解

    NRF52x开发环境搭建详解 准备 环境搭建 了解内存布局 Bootloader工程 APP工程 JFlash下载 打印log 准备 以下是项目开发环境搭建的一些文档或工具链接: 项目 链接 CPU ...

  10. “iOS 推送通知”详解:从创建到设置到运行

    "iOS 推送通知"详解:从创建到设置到运行 转自 http://www.csdn.net/article/2012-02-18/311976 这是一篇编译的文章,内容均出自Par ...

最新文章

  1. 想去Google做AI?先看完这套面试指南(附面试题)
  2. linux 检查权限,检查目录下 文件的权限-linux shell脚本,
  3. 【论文笔记】Sparse filtering
  4. 气象各种资料汇总(持续更新ing)
  5. 2019 ICPC 南京网络赛 F Greedy Sequence
  6. python 写入excel_一行一行整理EXCEL表太麻烦,试试python脚本,1秒写入数据
  7. excel npoi 连接_Net操作Excel_NPOI(示例代码)
  8. abap 转换成字符串_ABAP--关于字符串String到XString XString to String转换代码
  9. 有关使用sklearn LogisticRegression出现的 DeprecationWarning:
  10. Jquery—对$()的总结
  11. mybatis-plus中的select
  12. 大数据Hadoop(一):​​​​​​​Hadoop介绍
  13. Eprime 倒计时代码
  14. linux系统 ghost,Linux下用GHOST来做系统备份
  15. python求两数最小公倍数_Python自定义函数实现求两个数最大公约数、最小公倍数示例...
  16. 视频带宽(码流_分辨率_帧率)
  17. 反向的css动画,动画方向 | animation-direction
  18. 我的人生哲学(三十六岁版)
  19. java print 格式化输出_java 格式化输出方法
  20. java商品类_商品类目选择功能开发

热门文章

  1. 经验分享:Web前端入门要怎么开始学?
  2. J - 简单枚举类型——植物与颜色
  3. JAVA蓝桥杯:杨辉三角形
  4. 大数运算(Java)
  5. voc数据集的map计算方式
  6. Qt 信号槽 signals slots 特点 限定符的区别
  7. 关于单点登录的简单原理和实现步骤
  8. String去重方法
  9. 基于 HTML5 WebGL 的 3D 机房
  10. 最新的jQuery插件和JavaScript库