本文将带你了解IOS开发入门iOS 多线程编程(十五、RunLoop简单介绍),希望本文对大家学IOS有所帮助。
一:什么是RunLoop
(1)从字面意思看,运行循环、跑圈。
(2)保持程序持续运行,处理App中的各类事件包括触摸事件、定时器事件、Selector事件。
(3)节省CPU资源,提高程序的性能,该做事的时候做事,该休息的时候休息。
二:RunLoop与线程
(1)每条线程都有唯一的一个与之对应的RunLoop对象。
(2)主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建。
(3)RunLoop在第一次获取时创建,在线程结束时候销毁。
三:RunLoop相关类
Core Foundation中关于RunLoop的5个类
1:CFRunLoopRef
2:CFRunLoopModeRef
,CFRunLoopModeRef代表RunLoop的运行模式,一个RunLoop包含若干个运行模式,即一个RunLoop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer,每次RunLoop启动时,只能指定其中一个Mode,这个Mode被称作CurrentMode,如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入。系统默认注册了5个Mode:
(1)kCFRunLoopDefaultMode:App的默认的Mode,通常线程是在这个Mode下运行
(2)UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其它Mode影响
(3)UIInitializationRunLoopMode:在刚启动App时进入的第一个Mode,启动完成后就不再使用
(4)GSEventReceiveRunLoopMode:接收系统事件的内部Mode,通常用不到。
(5)kCFRunLoopCommonMode:这是一种占位用的Mode,不是一种真正的Mode。
3:CFRunLoopTimerRef
(1)CFRunLoopTimerRef是基于时间的触发器。
(2)基本上说的就是NSTimer,它会受到runloop的Mode的影响。
(3)GCD的定时器不受RunLoop的mode的影响。
关于定时器和runloopMode的关系如下代码
?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
ViewController.m// CFRunLoopTimerRef Created by fe on
2016/10/25.// Copyright © 2016年 fe. All rights reserved.// #import
"ViewController.h" @interface ViewController ()@property
(nonatomic , strong) dispatch_source_t timer;@end @implementation
ViewController -(void)touchesBegan:(NSSet *)touches
withEvent:(UIEvent *)event{ [self
GCDTimer]; } -(void)timer1{ /* 第一种定时器用法,这种方式创建的定时器, 系统默认添加到NSRunLoop中的NSDefaultRunLoopMode模式中, 但是当用户和应用交互发生触摸滑动等事件时, RunLoop的模式会切换到UITrackingRunLoopMode, 此时定时器就不再工作,因为定时器只在,默认被添加到的NSDefaultRunLoopMode 模式下工作。 */ [NSTimer
scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(go)
userInfo:nil
repeats:YES];}-(void)timer2{ /* 第二种定时器用法,这种方式创建的定时器,如果添加到NSRunLoop, 并设置RunLoop模式为NSDefaultRunLoopMode, 当用户和应用交互发生触摸滑动等事件时, RunLoop的模式会切换到UITrackingRunLoopMode, 此时定时器就不再工作,因为定时器只在NSDefaultRunLoopMode模式下工作。 如果把用这种方式创建的定时器,添加到NSRunLoop, 并设置RunLoop模式为UITrackingRunLoopMode, 在这种情况下,只有当用户和应用交互发生触摸滑动等事件时, 定时器才会工作。 为了解决以上两种RunLoop运行模式造成的定时器,定时不准的问题。 我们可以把定时器添加到RunLoop并设置运行模式为NSRunLoopCommonModes. 在这种运行模式下,不管是默认状态,还是当用户和应用交互发生触摸滑动等事件时。 定时器都可以正常工作。 */ //1:创建定时器 NSTimer
*timer = [NSTimer timerWithTimeInterval:2.0 target:self
selector:@selector(go) userInfo:nil
repeats:YES]; //2.1:把定时器添加到RunLoop中,定时器在NSDefaultRunLoopMode模式下工作。 //[[NSRunLoop
currentRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode]; //2.2:把定时器添加到RunLoop中,定时器在UITrackingRunLoopMode模式下工作。 //[[NSRunLoop
currentRunLoop] addTimer:timer
forMode:UITrackingRunLoopMode]; //2.3 /* 把定时器添加到RunLoop中,设置模式为NSRunLoopCommonModes, 定时器在UITrackingRunLoopMode模式和NSDefaultRunLoopMode模式下都工作。 NSRunLoopCommonModes是一种标记模式,被打上这种标记的模式有以下两种 0
: contents = "UITrackingRunLoopMode" 2
: contents =
"kCFRunLoopDefaultMode" */ [[NSRunLoop
currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; NSLog(@"---------%@",[NSRunLoop
currentRunLoop]); }-(void)GCDTimer{ /* 使用GCD的定时器,不会受到RunloopMode的影响。 */ //0:创建队列 dispatch_queue_t
queue = dispatch_queue_create("cn.520.www",
DISPATCH_QUEUE_CONCURRENT); //1:创建一个GCD定时器 dispatch_source_t
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
queue); self.timer =
timer; //2:设置定时器的开始时间,间隔时间,精确度。精准度一般填0,表示没有误差。 dispatch_source_set_timer(timer,
DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 *
NSEC_PER_SEC); //3:定时器要调用的方法。 dispatch_source_set_event_handler(timer,
^{ NSLog(@"----------%@",[NSThread
currentThread]); }); //4:启动定时器。 dispatch_resume(timer);}-(void)go{ NSLog(@"-----------");}@end
4:CFRunLoopSourceRef
(1)CFRunLoopSourceRef是事件源(输入源),分为两种。
(2)Source0:非基于Port的,用于用户主动触发的事件。
(3)Source1:基于Port的,通过内核和其它线程相互发送消息。
5:CFRunLoopObserverRef
(1)CFRunLoopObserverRef是观察者,能够监听RunLoop状态的改变。
(2)可以监听的时间点有一下几个
?12345678910/* Run Loop
Observer Activities */ typedef
CF_OPTIONS(CFOptionFlags, CFRunLoopActivity)
{ kCFRunLoopEntry = (1UL
<<
0),//即将进入loop kCFRunLoopBeforeTimers
= (1UL << 1),//即将处理timer kCFRunLoopBeforeSources
= (1UL <<
2),//即将处理Source kCFRunLoopBeforeWaiting
= (1UL <<
5),//即将进入休眠 kCFRunLoopAfterWaiting
= (1UL <<
6),//即将从休眠中唤醒 kCFRunLoopExit =
(1UL <<
7),//即将推出RunLoop kCFRunLoopAllActivities
= 0x0FFFFFFFU//监听所有状态 };
和CFRunLoopObserverRef相关的代码如下:
?1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253-(void)observer{ /* 第一个参数:开辟内存空间 第二个参数:监听runloop的什么事件 第三个参数:是否持续监听 第四个参数:优先级 第五个参数:回掉 */ CFRunLoopObserverRef
observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(),
kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer,
CFRunLoopActivity activity)
{ switch
(activity){ case
kCFRunLoopEntry: NSLog(@"--runloop即将进入循环--"); break; case
kCFRunLoopBeforeTimers: NSLog(@"--runloop将要处理timer--"); break; case
kCFRunLoopBeforeSources: NSLog(@"--runloop将要处理sources--"); break; case
kCFRunLoopBeforeWaiting: NSLog(@"--runloop将要进入休眠--"); break; case
kCFRunLoopAfterWaiting: NSLog(@"--runloop休眠结束即将进入循环--"); break; case
kCFRunLoopExit: NSLog(@"--runloop退出循环--"); break; default: break; } }); /* 第一个参数:要监听哪一个runloop 第二个参数:监听者 第三个参数:要监听runloop在哪种运行模式下的状态 */ CFRunLoopAddObserver(CFRunLoopGetCurrent(),
observer, kCFRunLoopDefaultMode); }
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之IOS频道!