深入理解RunLoop 整理资料

http://blog.ibireme.com/2015/05/18/runloop/#base

// RunLoop学习笔记,从CF层面了解由于CFRunLoopMode机制iOS程序ScrollView的滑动为何如此平滑的原因。还有介绍AFNetworking如何单独发起一个global thread内置runloop达到不占用主线程又不耗CPU资源的。

// 简单的说run loop是事件驱动的一个大循环,如下代码所示

int main(int argc, char * argv[]) {

//程序一直运行状态

while (AppIsRunning) {

//睡眠状态,等待唤醒事件

id whoWakesMe = SleepForWakingUp();

//得到唤醒事件

id event = GetEvent(whoWakesMe);

//开始处理事件

HandleEvent(event);

}

return 0;

}

//  Cocoa会涉及到Run Loops的

//系统级:GCD,mach kernel,block,pthread

// 应用层:NSTimer,UIEvent,Autorelease,NSObject(NSDelayedPerforming),NSObject(NSThreadPerformAddition),CADisplayLink,CATransition,CAAnimation,dispatch_get_main_queue()(GCD中dispatch到main queue的block会被dispatch到main RunLoop执行),NSPort,NSURLConnection,AFNetworking(这个第三方网络请求框架使用在开启新线程中添加自己的run loop监听事件)

// 在Main thread堆栈中所处位置

//堆栈最底层是start(dyld),往上依次是main,UIApplication(main.m) -> GSEventRunModal(Graphic Services) -> RunLoop(包含CFRunLoopRunSpecific,CFRunLoopRun,__CFRunLoopDoSouces0,__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION) -> Handle Touch Event

//RunLoop原理

//执行顺序的伪代码

SetupThisRunLoopRunTimeoutTimer(); // by GCD timer

do {

__CFRunLoopDoObservers(kCFRunLoopBeforeTimers);

__CFRunLoopDoObservers(kCFRunLoopBeforeSources);

__CFRunLoopDoBlocks();

__CFRunLoopDoSource0();

CheckIfExistMessagesInMainDispatchQueue(); // GCD

__CFRunLoopDoObservers(kCFRunLoopBeforeWaiting);

var wakeUpPort = SleepAndWaitForWakingUpPorts();

// mach_msg_trap

// Zzz...

// Received mach_msg, wake up

__CFRunLoopDoObservers(kCFRunLoopAfterWaiting);

// Handle msgs

if (wakeUpPort == timerPort) {

__CFRunLoopDoTimers();

} else if (wakeUpPort == mainDispatchQueuePort) {

// GCD

__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()

} else {

__CFRunLoopDoSource1();

}

__CFRunLoopDoBlocks();

} while (!stop && !timeout);

//  构成

//Thread包含一个CFRunLoop,一个CFRunLoop包含一种CFRunLoopMode,mode包含CFRunLoopSource,CFRunLoopTimer和CFRunLoopObserver。

CFRunLoopMode

// RunLoop只能运行在一种mode下,如果要换mode当前的loop也需要停下重启成新的。利用这个机制,ScrollView过程中NSDefaultRunLoopMode的mode会切换UITrackingRunLoopMode来保证ScrollView的流畅滑动不受只能在NSDefaultRunLoopMode时处理的事件影响滑动。同时mode还是可定制的。

NSDefaultRunLoopMode:        默认,空闲状态

UITrackingRunLoopMode:       ScrollView滑动时

UIInitializationRunLoopMode: 启动时

NSRunLoopCommonModes:        Mode集合 Timer计时会被scrollView的滑动影响的问题可以通过将timer添加到NSRunLoopCommonModes来解决

//将timer添加到NSDefaultRunLoopMode中

[NSTimer scheduledTimerWithTimeInterval:1.0

target:self

selector:@selector(timerTick:)

userInfo:nil

repeats:YES];

//然后再添加到NSRunLoopCommonModes里

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0

target:self

selector:@selector(timerTick:)

userInfo:nil

repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

CFRunLoopTimer

//NSTimer是对RunLoopTimer的封装

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;

+ (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel;

- (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSString *)mode;

CFRunLoopSource

//    source0:处理如UIEvent,CFSocket这样的事件

//    source1:Mach port驱动,CFMachport,CFMessagePort

//    CFRunLoopObserver

//

//    Cocoa框架中很多机制比如CAAnimation等都是由RunLoopObserver触发的。observer到当前状态的变化进行通知。

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {

kCFRunLoopEntry = (1UL << 0),

kCFRunLoopBeforeTimers = (1UL << 1),

kCFRunLoopBeforeSources = (1UL << 2),

kCFRunLoopBeforeWaiting = (1UL << 5),

kCFRunLoopAfterWaiting = (1UL << 6),

kCFRunLoopExit = (1UL << 7),

kCFRunLoopAllActivities = 0x0FFFFFFFU

};

//使用RunLoop的案例

AFNetworking

//使用NSOperation+NSURLConnection并发模型都会面临NSURLConnection下载完成前线程退出导致NSOperation对象接收不到回调的问题。AFNetWorking解决这个问题的方法是按照官方的guidhttps://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html#//apple_ref/occ/instm/NSURLConnection/initWithRequest:delegate:startImmediately:上写的NSURLConnection的delegate方法需要在connection发起的线程runloop中调用,于是AFNetWorking直接借鉴了Apple自己的一个Demohttps://developer.apple.com/LIBRARY/IOS/samplecode/MVCNetworking/Introduction/Intro.html的实现方法单独起一个global thread,内置一个runloop,所有的connection都由这个runloop发起,回调也是它接收,不占用主线程,也不耗CPU资源。

+ (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;

}

//    类似的可以用这个方法创建一个常驻服务的线程。

//

//    TableView中实现平滑滚动延迟加载图片

//

//    利用CFRunLoopMode的特性,可以将图片的加载放到NSDefaultRunLoopMode的mode里,这样在滚动UITrackingRunLoopMode这个mode时不会被加载而影响到。

UIImage *downloadedImage = ...;

[self.avatarImageView performSelector:@selector(setImage:)

withObject:downloadedImage

afterDelay:0

inModes:@[NSDefaultRunLoopMode]];

//接到程序崩溃时的信号进行自主处理例如弹出提示等

CFRunLoopRef runLoop = CFRunLoopGetCurrent();

NSArray *allModes = CFBridgingRelease(CFRunLoopCopyAllModes(runLoop));

while (1) {

for (NSString *mode in allModes) {

CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);

}

}

异步测试

- (BOOL)runUntilBlock:(BOOL(^)())block timeout:(NSTimeInterval)timeout

{

__block Boolean fulfilled = NO;

void (^beforeWaiting) (CFRunLoopObserverRef observer, CFRunLoopActivity activity) =

^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {

fulfilled = block();

if (fulfilled) {

CFRunLoopStop(CFRunLoopGetCurrent());

}

};

CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, beforeWaiting);

CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

// Run!

CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, false);

CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

CFRelease(observer);

return fulfilled;

}

}

时间: 2024-10-14 05:39:40

深入理解RunLoop 整理资料的相关文章

深入理解Runloop,看我一篇就够了

前言 RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,为了让大家更加快速融入,请先一段代码: + (NSThread *)networkRequestThread { static NSThread *_networkRequestThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ _networkRequestThread = [[NSThread alloc

1、Android项目框架搭建 (分析需求、整理资料)

闲来无事.想搭个框架试试 分析一般应用 将资料整理整理 粗略统计 需要以下资料 1.android-pulltorefresh 一个强大的拉动刷新开源项目,支持各种控件下拉刷新 ListView.ViewPager.WevView.ExpandableListView.GridView.(Horizontal )ScrollView.Fragment上下左右拉动刷新,比下面johannilsson那个只支持ListView的强大的多.并且他实现的下拉刷新ListView在item不足一屏情况下也

FPGA整理资料

1.寄存器与锁存器 锁存器:电平触发的存储单元,在有效电平时间里可以多次改变数据. 优点:    占触发器资源少,缺点是容易产生毛刺.(附上去毛刺的方法:格雷码计数器(*https://blog.csdn.net/qp314/article/details/5147695*)代替二进制码计数器,或者用D触发器同步.) 在FPGA中用的很少,因为FPGA中触发器的资源非常丰富. 寄存器:边沿触发的存储单元,在上升或下降沿数据变化,一个周期里只能变化一次.(寄存器是有DFF(D触发器)构成的,它起的

iOS开发--1.对runtime的理解和整理

在我以往的面试中常常会被问到runtime,开始本人其实对runtime只是个简单的了解,用过一些常用的功能,并未仔细研究.不过看来现在iOS开发越来越关注runtime了,所有工作之余仔细查看了一些大牛的博客.本篇文章只是对一些大牛博客的整理,还有一些自己对runtime的不成熟的理解,只是为了方便学习.希望大家多多指点批评 附带上大牛博客:onevcat的博客:runtime的博客 一:基本概念 Runtime简称运行时,基本是用汇编和C语言编写的,只是苹果为了动态系统的高效而作出的努力.点

深入理解RunLoop

RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何利用 RunLoop 实现自动释放池.延迟回调.触摸事件.屏幕刷新等功能的. RunLoop 的概念 一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出.如果我们需要一个机制,让线程能随时处理事件但并不退出,通常的代码逻辑是这样的: 1 2 3 4 5 6 7 function loop(

转载 -- 深入理解RunLoop

RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何利用 RunLoop 实现自动释放池.延迟回调.触摸事件.屏幕刷新等功能的. IndexRunLoop 的概念RunLoop 与线程的关系RunLoop 对外的接口RunLoop 的 ModeRunLoop 的内部逻辑RunLoop 的底层实现苹果用 RunLoop 实现的功能AutoreleaseP

iOS 深入理解RunLoop

RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何利用 RunLoop 实现自动释放池.延迟回调.触摸事件.屏幕刷新等功能的. IndexRunLoop 的概念RunLoop 与线程的关系RunLoop 对外的接口RunLoop 的 ModeRunLoop 的内部逻辑RunLoop 的底层实现苹果用 RunLoop 实现的功能AutoreleaseP

(转)hashCode()、equals()以及compareTo()方法的理解 (整理)

http://crd1991.iteye.com/blog/1473108 http://blog.csdn.net/liushuai_ly/article/details/8197508 判断两个对象是否相等(是同一个对象),首先调用hashCode()方法得到各自的hashcode, 1.如果hashcode不相等,则表明两个对象不相等. 2.如果hashcode相等,继续调用equals方法进行判断 2.1:equals()返回true,则对象相等 2.2:equals()返回fasle,

MVC框架理解(整理)

MVC是三个单词的首字母缩写,它们是Model(模型).View(视图)和Controller(控制). 视图 视图(View)代表用户交互界面,对于Web应用来说,可以概括为HTML界面,但有可能为XHTML.XML和Applet.随着应用的复杂性和规模性,界面的处理也变得具有挑战性.一个应用可能有很多不同的视图,MVC设计模式对于视图的处理仅限于视图上数据的采集和处理,以及用户的请求,而不包括在视图上的业务流程的处理.业务流程的处理交予模型(Model)处理.比如一个订单的视图只接受来自模型