runloop和时间片

前一篇<<postNotificationName同步调用导致的白屏问题>>里讲到"mediaView里抛通知时在异步线程抛,利用线程切换避免reloadData过程中再reloadData”.

为何这样做可以解决问题呢?

在异步线程(假设是thread10)抛HWCHAT_VIEW_NEED_RELOAD
通知,导致在thread10里同步调用了reloadChatCollectionViewData。因为在reloadChatCollectionViewData里进行了线程切换:yoho_dispatch_execute_in_main_queue,
切回到

主线程执行reloadData。

这样执行reloadData为何避免了reloadData过程中再reloadData呢?

下面涉及到runloop的问题。

看出问题时的log:

2015-03-25 10:44:40:168 demo[2957:807] Debug|[HWChatManager.m 175]: __45-[HWChatManager reloadChatCollectionViewData]_block_invoke 抛通知HWCHAT_VIEW_NEED_RELOAD

2015-03-25 10:44:40:168 demo[2957:807] Debug|[HWChatViewController.m 162]: -[HWChatViewController reloadChatCollectionViewData] 111111*********

2015-03-25 10:44:40:169 demo[2957:807] Debug|[HWChatViewController.m 164]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke
22222==========

2015-03-25 10:44:40:206 demo[2957:807] Debug|[HWPhotoMediaItem.m 41]: __29-[HWPhotoMediaItem mediaView]_block_invoke_2
抛通知HWCHAT_VIEW_NEED_RELOAD

2015-03-25 10:52:59:275 demo[2957:807] Debug|[HWChatViewController.m 162]: -[HWChatViewController reloadChatCollectionViewData]
111111*********

2015-03-25 10:52:59:275 demo[2957:807] Debug|[HWChatViewController.m 164]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke
22222==========

2015-03-25 10:52:59:277 demo[2957:807] Debug|[HWChatViewController.m 167]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke
33333+++++++++++

807是主线程id,在主线程调用了[HWChatViewController reloadChatCollectionViewData],reloadData时导致[HWPhotoMediaItem mediaView]在主线程抛通知HWCHAT_VIEW_NEED_RELOAD,[HWChatViewController
reloadChatCollectionViewData]做为观察者的selector又执行了一次reloadData导致白屏。

这些动作都是在主线程的runloop的一次pass(循环的一次遍历,暂命名passA)里执行的。

主线程中, mediaView里抛通知时改为在异步线程抛。那么,进程需要等到线程切换时,才能切到异步线程thread10。

进程得到时间片进行线程切换,进入线程10.

thread10抛通知HWCHAT_VIEW_NEED_RELOAD, [HWChatViewController reloadChatCollectionViewData]做为观察者的selector在thread10中执行:

-(void)reloadChatCollectionViewData {
    HWLog(@"111111*********");
    yoho_dispatch_execute_in_main_queue(^{
        HWLog(@"22222==========");
        [_collectionView reloadData];
        [_collectionView layoutIfNeeded];
        HWLog(@"33333+++++++++++");
        [_collectionView scrollToBottomAnimated:YES];
    });
}

然后reloadChatCollectionViewData里yoho_dispatch_execute_in_main_queue又切回到主线程。

这些动作是在thread10的runloop的一次pass(假设是passB)里执行的

那么,进程需要等到线程切换时,才能切到主线程执行reloadData。

进程得到时间片进行线程切换,再进入主线程执行passC。此时passA早已经执行完成,即之前的reloadData已完成执行。

那么passC中执行reloadData当然和之前的reloadData没有关系了,避免了"reloadData过程中再reloadData”。

无问题时的log如下:

2015-03-25 11:50:52:145 demo[10982:807] Warn|[HWRecentTableViewController.m 214]: -[HWRecentTableViewController
reloadQLMessage] 重新加载列表

2015-03-25 11:50:52:748 demo[10982:ce17] Debug|[HWPhotoMediaItem.m 41]: __29-[HWPhotoMediaItem mediaView]_block_invoke_2
抛通知HWCHAT_VIEW_NEED_RELOAD

2015-03-25 11:50:52:748 demo[10982:2507] Debug|[HWPhotoMediaItem.m 41]: __29-[HWPhotoMediaItem mediaView]_block_invoke_2
抛通知HWCHAT_VIEW_NEED_RELOAD

2015-03-25 11:50:52:748 demo[10982:ce17] Debug|[HWChatViewController.m 164]: -[HWChatViewController reloadChatCollectionViewData]
111111*********

2015-03-25 11:50:52:748 demo[10982:2507] Debug|[HWChatViewController.m 164]: -[HWChatViewController reloadChatCollectionViewData]
111111*********

2015-03-25 11:50:52:750 demo[10982:807] Debug|[HWChatViewController.m 166]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke
22222==========

2015-03-25 11:50:52:777 demo[10982:807] Debug|[HWChatViewController.m 169]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke
33333+++++++++++

2015-03-25 11:50:52:777 demo[10982:807] Debug|[HWChatViewController.m 166]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke
22222==========

2015-03-25 11:50:52:804 demo[10982:807] Debug|[HWChatViewController.m 169]: __52-[HWChatViewController reloadChatCollectionViewData]_block_invoke
33333+++++++++++

最后再描述一下runloop. 为了好解释,以单cpu情形为例。

程序能不断地处理用户点击或者网络事件, 是因为runloop的驱动,不然,cpu执行完指令不是应该立刻退出程序了吗?

runloop可以理解为你用手臂在水里不断划圈,驱动了水的转动(程序的执行)。你的手臂划一个完整的圆圈,这一个圆圈,就是上面提的一个pass。

理解runloop也可以结合cpu时间片。

进程得到cpu时间片后,在某个线程的runloop的某次pass里执行,执行时如果遇到网络请求或磁盘io或其他原因导致出让cpu,此次pass结束执行。

后面进程再获得cpu时间片得以运行时,就是在下一个pass里执行了。

时间: 2024-11-15 15:37:02

runloop和时间片的相关文章

李洪强iOS开发之RunLoop的原理和核心机制

李洪强iOS开发之RunLoop的原理和核心机制 搞iOS之后一直没有深入研究过RunLoop,非常的惭愧.刚好前一阵子负责性能优化项目,需要利用RunLoop做性能优化和性能检测,趁着这个机会深入研究了RunLoop的原理和特性. RunLoop的定义 当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程.RunLoop就是控制线程生命周期并接收事件进行处理的机制. RunLoop是iOS事件响应与任务处理最核心的机制,它贯穿iOS整个系统. Foundation: NSRunLo

iOS 中RunLoop 原理与核心机制

目录[-] RunLoop的定义 目的 理解 特性 RunLoop机制 RunLoop 运行时调用栈 RunLoop支持的消息事件(Events) Run Loop Modes Run Loop应用实践 RunLoop的定义 当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程.RunLoop就是控制线程生命周期并接收事件进行处理的机制. RunLoop是iOS事件响应与任务处理最核心的机制,它贯穿iOS整个系统. Foundation: NSRunLoopCore Foundati

iOS Runloop理解

一.RunLoop的定义 当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程.RunLoop就是控制线程生命周期并接收事件进行处理的机制. RunLoop是iOS事件响应与任务处理最核心的机制,它贯穿iOS整个系统. Foundation: NSRunLoopCore Foundation: CFRunLoop 核心部分,代码开源,C 语言编写,跨平台 二.目的 通过RunLoop机制实现省电,流畅,响应速度快,用户体验好 三.理解 进程是一家工厂,线程是一个流水线,Run Loo

iOS开发-RunLoop总结

序言 在<iOS之应用程序启动过程及原理总结>一篇中介绍了iOS应用的启动原理.我们知道当应用启动后,系统会自动创建一个线程来执行任务,该线程被称为主线程或者UI线程.其实在主线程创建的时候,系统还会为主线程创建并启动一种机制(其实就是一个对象,该对象和应用的生命周期有关),叫做RunLoop,被称为运行循环机制.本文主要将介绍iOS应用中的RunLoop机制. RunLoop简介 RunLoop概念 提到RunLoop,我们一般都会提到线程,这是为什么呢?先来看下 官方对 RunLoop 的

NSURLConnection和Runloop(面试)

(1)两种为NSURLConnection设置代理方式的区别 //第一种设置方式: //通过该方法设置代理,会自动的发送请求 // [[NSURLConnection alloc]initWithRequest:request delegate:self]; //第二种设置方式: //设置代理,startImmediately为NO的时候,该方法不会自动发送请求 NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:

【iOS程序启动与运转】- RunLoop个人小结

学习iOS开发一般都是从UI开始的,从只知道从IB拖控件,到知道怎么在方法里写代码,然后会显示什么样的视图,产生什么样的事件,等等.其实程序从启动开始,一直都是按照苹果封装好的代码运行着,暴露的一些属性和方法作为接口,是让我们在给定的方法里写代码实现自定义功能,做出各种各样的应用.这些方法的调用顺序最为关键,熟悉了程序运转和方法调用的顺序,才可以更好地操控程序和代码,尽量避免Xcode不报错又实现不了功能的BUG.从Xcode的线程函数调用栈可以看到一些方法调用顺序. 0 从程序启动开始到vie

Runloop

1.Runloop基础知识 1.1 字面意思 a 运行循环 b 跑圈 1.2 基本作用(作用重大) a 保持程序的持续运行(ios程序为什么能一直活着不会死) b 处理app中的各种事件(比如触摸事件.定时器事件[NSTimer].selector事件[选择器·performSelector···]) c 节省CPU资源,提高程序性能,有事情就做事情,没事情就休息 1.3 重要说明 (1)如果没有Runloop,那么程序一启动就会退出,什么事情都做不了. (2)如果有了Runloop,那么相当于

IOS RunLoop浅析 一

RunLoop犹如其名循环. RunLoop 中有多重模式. 在一个"时刻"只能值执行一种模式. 因此在使用RunLoop时要注意所实现的效果有可能不是你想要的. 在这里用NSTimer展示一下Runloop的简单实现. 在故事板中添加一个TextView(用于测试) 我们吧nstimer加入到NSDefaultRunLoopMode模式中 在上面我们可以很清晰的看到,当我们滚动TextView的时候,nstimer不在执行. // // ViewController.m // CX

iOS 如何启动和停止RunLoop

#import "ViewController.h" @interface ViewController ()<NSURLConnectionDataDelegate> @property (nonatomic, assign) CFRunLoopRef runLoop;// 保持同一个线程 C语言 @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; dispatch_