iOS 中Runloop

Runloop 字面理解为运行循环

作用:
1,保持程序的持续运行。
2,处理程序中的各种事件,比如触摸事件,定时器事件。Selector方法。
3,节省CPU资源,提高程序性能。该做事时做事,该休息时休息(Runloop的状态)

iOS中有两套API访问Runloop
1,Foundation框架
NSRunloop
2,Core Foundation框架
CFRunloopRef

NSRunloop是基于CFRunloopRef的封装

一,runloop与线程的关系
1,每条线程都有唯一的一个与之对应的runloop
2,主线程的runloop已经自动创建好了,子线程的runloop需要主动创建。
3,runloop在第一次获取时创建,在线程结束时销毁。

二,CFRunloopModeRef
CFRunloopModeRef代表Runloop的运行模式
1,一个Runloop包含多个运行模式Mode,每个Mode又包含若干个Source/Timer/Observer。
2,每次Runloop启动时只能启动一个mode,称之为currentmode,可通过此方法获取。
3,如果要切换mode,只能先退出loop,再重新指定一个Mode进入。

系统默认为我们注册了5种运行模式,这里只介绍公开暴露出来的两种

NSDefaultRunLoopMode 默认Mode,通常主线程运行模式。
NSEventTrackingRunLoopMode 界面跟踪Mode,ScrollView追踪滑动触摸,保证界面滑动时不受其他Mode影响。
NSRunLoopCommonModes 标签,被标记的对象可以运行在被标签标记的模式下,随着模式的切换而切换,比如NSTimer。

iOS 中公开暴露出来的只有 NSDefaultRunLoopMode 和 NSRunLoopCommonModes。 NSRunLoopCommonModes 实际上是一个 Mode 的集合,默认包括 NSDefaultRunLoopMode 和 NSEventTrackingRunLoopMode(注意:并不是说Runloop会运行在kCFRunLoopCommonModes这种模式下,而是相当于分别注册了 NSDefaultRunLoopMode和 UITrackingRunLoopMode。当然你也可以通过调用CFRunLoopAddCommonMode()方法将自定义Mode放到 kCFRunLoopCommonModes组合)。

三,CFRunLoopSourceRef
以前分类:
1,Port
2,Custom,Input Source
3,performselector
现在:
1,Source0:
非基于port的,用户主动触发的,如触摸等
2,Source1:
基于Port的,基于内核和其他线程相互发送消息。

四,CFRunLoopObserverRef
CFRunLoopObserver是观察者,可以观察RunLoop的各种状态,并抛出回调。

struct __CFRunLoopObserver {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;
    CFIndex _rlCount;
    CFOptionFlags _activities;      /* immutable */
    CFIndex _order;         /* immutable */
    CFRunLoopObserverCallBack _callout; /* immutable */
    CFRunLoopObserverContext _context;  /* immutable, except invalidation */
};

CFRunLoopObserver可以观察的状态有如下6种:

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), //即将进入run loop
    kCFRunLoopBeforeTimers = (1UL << 1), //即将处理timer
    kCFRunLoopBeforeSources = (1UL << 2),//即将处理source
    kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),//被唤醒但是还没开始处理事件
    kCFRunLoopExit = (1UL << 7),//run loop已经退出
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};
什么是Runloop?

字面意思是一个运行循环,其实内部是一个do while 循环,在处理各种事件,timer,source,Observer。
一个线程对应一个Runloop。主线程自动启动,子线程需要手动启动,调用Run方法。
Runloop只能选择一个模式启动,更改模式需要先退出再进入新模式。如果Model没有任何timer。source,那么直接退出runloop。

自动释放池什么时候释放?

根据Observer观察的Runloop状态释放,runloop退出。

五,Runloop应用
1,NSTimer
定时器设置为CommonMode更精准
2,ImageVIew显示
将图片的显示设置在UITracking模式,可以保证在列表滑动的时候依然能够加载视图。
3,PerformSeletor
4,常驻线程
创建一个Runloop在子线程一直运行,保证线程在后台常驻(AFNetworking源码)。

子线程的Runloop需要手动调用,然后添加一个Source或者Timer事件,再调用Run方法。

5,自动释放池
Runloop内部会自动创建一个自动释放池,开始的时候创建,等到合适的时机再释放,通过观察Runloop状态来进行。

6,通过对Runloop添加Observer来做一些事情
(1),比如监听点击事件,当runloop处理点击事件时候可以统一做一些事情。
(2),也可以通过对Runloop状态的观察来检测系统卡顿,当长时间处于一个模式不变就是出现了卡顿。

//创建子线程监控
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    //子线程开启一个持续的 loop 用来进行监控
    while (YES) {
        long semaphoreWait = dispatch_semaphore_wait(dispatchSemaphore, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC));
        if (semaphoreWait != 0) {
            if (!runLoopObserver) {
                timeoutCount = 0;
                dispatchSemaphore = 0;
                runLoopActivity = 0;
                return;
            }
            //BeforeSources 和 AfterWaiting 这两个状态能够检测到是否卡顿
            if (runLoopActivity == kCFRunLoopBeforeSources || runLoopActivity == kCFRunLoopAfterWaiting) {
                //将堆栈信息上报服务器的代码放到这里
            } //end activity
        }// end semaphore wait
        timeoutCount = 0;
    }// end while
});

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • ======================= 前言 RunLoop 是 iOS 和 OSX 开发中非常基础的一个...
    i憬铭阅读 826评论 0 4
  • 概述 RunLoop作为iOS中一个基础组件和线程有着千丝万缕的关系,同时也是很多常见技术的幕后功臣。尽管在平时多...
    sumrain_cloud阅读 939评论 0 5
  • 1.不开启RunLoop的线程在遇到一些耗时操作时,为了避免主线程阻塞导致界面卡顿,影响用户体验,往往我们会把这些...
    shinedada阅读 351评论 0 2
  • 本文我主要是学习如下文章做的记录,同时还有其他优秀的文章没有粘贴出来,在这里均表示感谢。iOS RunLoop入门...
    wg刚阅读 322评论 0 1
  • 转自bireme,原地址:https://blog.ibireme.com/2015/05/18/runloop/...
    乜_啊_阅读 1,211评论 0 5