iOS runloop 详解5
2016-08-04 11:11
776 查看
//
// ViewController.m
// test_runloop_01
//
// Created by jeffasd on 16/7/25.
// Copyright © 2016年 jeffasd. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, assign) BOOL isRuning;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_isRuning = YES;
BOOL isSuccess = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
NSLog(@"runLoop is %@", isSuccess ? @"YES" : @"NO");
NSLog(@"runloop is %@", [NSRunLoop currentRunLoop]);
#if 0
//苹果公开提供的 Mode 有两个:kCFRunLoopDefaultMode (NSDefaultRunLoopMode) 和 UITrackingRunLoopMode,你可以用这两个 Mode Name 来操作其对应的 Mode。
[[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate distantFuture]];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//同时苹果还提供了一个操作 Common 标记的字符串:kCFRunLoopCommonModes (NSRunLoopCommonModes),你可以用这个字符串来操作 Common Items,或标记一个 Mode 为 "Common"。使用时注意区分这个字符串和其他 mode name。
//commonModeItems
//这里使用的模式是:NSRunLoopCommonModes,这个模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的结合。
//运行在此模式下 commonModeItems 内 每当 RunLoop 的内容发生变化时,RunLoop 都会自动将 commonModeItems 里的 Source/Observer/Timer 同步到具有 "Common" 标记的所有Mode里。由于主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为"Common"属性。
//所以NSRunLoopCommonModes此模式会处理 来自UITrackingRunLoopMode和NSDefaultRunLoopMode内的时间
//设置主线程的运行模式为NSRunLoopCommonModes 主线程可以接受来自NSDefaultRunLoopMode和UITrackingRunLoopMode模式下的事件
// [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
NSTimer *timer = nil;
//将 Timer 加入到顶层的 RunLoop 的 "commonModeItems" 中。"commonModeItems" 被 RunLoop 自动更新到所有具有"Common"属性的 Mode 里去。
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
#endif
// NSLog(@"the runloop is %@", [NSRunLoop currentRunLoop]);
[NSThread detachNewThreadSelector:@selector(doSomething) toTarget:self withObject:nil];
}
- (void)doSomething{
_timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerDoSomething) userInfo:nil repeats:YES];
NSLog(@"therad is %@", [NSThread currentThread]);
NSLog(@"doSomething");
NSLog(@"the runloop is %@", [NSRunLoop currentRunLoop]);
// [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
// [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:UITrackingRunLoopMode];
// - (void)run; 无条件运行
// 不建议使用,因为这个接口会导致Run Loop永久性的运行在NSDefaultRunLoopMode模式,即使使用CFRunLoopStop(runloopRef);也无法停止Run Loop的运行,那么这个子线程就无法停止,只能永久运行下去。
// [[NSRunLoop currentRunLoop] run];
/*
如果是使用NSRunLoop,有三个运行的接口:
//1。运行 NSRunLoop,运行模式为默认的NSDefaultRunLoopMode模式,没有超时限制
无法使用CFRunLoopStop(runLoopRef)来停止RunLoop的运行
- (void)run;
//2.运行 NSRunLoop: 参数为运行模式、时间期限,返回值为YES表示是处理事件后返回的,NO表示是超时或者停止运行导致返回的。[Update]: 感谢网友olo的提醒:返回值只有在RunLoop没有运行的情况下才返回NO。比如:1)没有添加输入源和定时器源 2)mode为NSRunLoopCommonModes 或UITrackingRunLoopMode 等“非法”参数。如果超时的话返回YES,即使limitDate的初始值小于当前的Date,RunLoop也会执行一次然后马上返回YES。
- (BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate;
//3.运行 NSRunLoop: 参数为运时间期限,运行模式为默认的NSDefaultRunLoopMode模式
无法使用CFRunLoopStop(runLoopRef)来停止RunLoop的运行
- (void)runUntilDate:(NSDate *)limitDate;
建议是使用第二个接口来运行,因为它能够设置Run Loop的运行参数最多,而且最重要的是可以使用CFRunLoopStop(runLoopRef)来停止Run Loop的运行,而第一个和第三个接口无法使用CFRunLoopStop(runLoopRef)来停止Run Loop的运行。
*/
#if 0
//子线程中 设置 runloop的运行模式 为 NSDefaultRunLoopMode 子线程可以接受来自NSDefaultRunLoopMode模式下的事件
// BOOL isSuccess1 = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//设置子线程的运行模式为NSRunLoopCommonModes 子线程可以接受来自NSDefaultRunLoopMode和UITrackingRunLoopMode模式下的事件 但是对于子线程和主线程有一点不同是,主线程默认已经创建了两个 runloop NSDefaultRunLoopMode和UITrackingRunLoopMode 因此主线程设置 运行在此模式下能直接 接受 NSDefaultRunLoopMode和UITrackingRunLoopMode两个模式的事件,但是由于子线程 的runloop 为空,因此 要先给子线程的runloop添加一个模式上面的[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];及时在给子线程添加一个运行模式。
// BOOL isSuccess = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
//UITrackingRunLoopMode 只能在主线程中使用 子线程中不能使用
BOOL isSuccess = [[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate distantFuture]];
BOOL isSuccess1 = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
NSLog(@"runLoop is %@", isSuccess1 ? @"YES" : @"NO");
NSLog(@"runLoop is %@", isSuccess ? @"YES" : @"NO");
#endif
//对于子线程UITrackingRunLoopMode 参数无效, NSRunLoopCommonModes参数必须在本线程已经被添加过runloop后才有效
// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
// [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
//
// 可以使用CFRunLoopStop(runLoopRef)来停止RunLoop的运行
// CFRunLoopRun();
// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
BOOL ret = 0;
while (_isRuning)
{
// ret = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
// CADisplayLink *ling = [CADisplayLink displayLinkWithTarget:<#(nonnull id)#> selector:<#(nonnull SEL)#>];
// ling addToRunLoop:<#(nonnull NSRunLoop *)#> forMode:<#(nonnull NSString *)#>
//这样写相当于只写了一个while循环 runloop根本没有成功运行 NSRunLoopCommonModes 只对NSTimer和CADisplayLink,NSPort
//NSURLConnection等可以添加到runloop内运行的对象有效,这个NSRunLoopCommonModes是讲这些对象加入到commonItems内,然后将commitItems内
//的发生的事件 发送给 具有 common标记的runloop
//主线程的NSLog(@"runloop is %@", [NSRunLoop currentRunLoop]);
//打印的值为
// common modes = <CFBasicHash 0x7f9db8e012a0 [0x107b28a40]>{type = mutable set, count = 2,
// entries =>
// 0 : <CFString 0x108a5f210 [0x107b28a40]>{contents = "UITrackingRunLoopMode"}
// 2 : <CFString 0x107b495e0 [0x107b28a40]>{contents = "kCFRunLoopDefaultMode"}
// }
// ,
// common mode items = <CFBasicHash 0x7f9db8e014b0 [0x107b28a40]>{type = mutable set, count = 18,
//说明具有common标记的runloop有两个 一个是UITrackingRunLoopMode 一个是kCFRunLoopDefaultMode
//在common mode items 内发生的所有事件都会传递给具有common标记的runloop中 也就是 common mode items 内发生的所有事件都会传递给
//UITrackingRunLoopMode 一个是kCFRunLoopDefaultMode 但是对于主线程的runloop的运行模式 是有主线程负责的
//对于NSRunLoopCommonModes 准确是这个模式是将NSTimer和CADisplayLink,NSPort
//NSURLConnection等 添加到common mode items 内
//对于主线程由于主线程已经具备了两个runloop
NSDefaultRunLoopMode:App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
UIInitializationRunLoopMode:在刚启动App时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
NSRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的Mode
BOOL isRuning = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
NSLog(@"is runing %@", isRuning ? @"YES" : @"NO");
[[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]]
}
NSLog(@"exiting runloop.........: %d", ret);
// [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
// sleep(10);
// [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget:self];
// CFRunLoopStop([NSRunLoop currentRunLoop].getCFRunLoop);
// [[NSRunLoop currentRunLoop] run];
}
- (void)timerDoSomething{
static int i = 0;
i++;
if (i >= 4) {
CFRunLoopStop([NSRunLoop currentRunLoop].getCFRunLoop);
// CFRunLoopStop(CFRunLoopGetCurrent());
_isRuning = NO;
}
NSLog(@"timerDoSomething");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
_isRuning = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
// ViewController.m
// test_runloop_01
//
// Created by jeffasd on 16/7/25.
// Copyright © 2016年 jeffasd. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, assign) BOOL isRuning;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_isRuning = YES;
BOOL isSuccess = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
NSLog(@"runLoop is %@", isSuccess ? @"YES" : @"NO");
NSLog(@"runloop is %@", [NSRunLoop currentRunLoop]);
#if 0
//苹果公开提供的 Mode 有两个:kCFRunLoopDefaultMode (NSDefaultRunLoopMode) 和 UITrackingRunLoopMode,你可以用这两个 Mode Name 来操作其对应的 Mode。
[[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate distantFuture]];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//同时苹果还提供了一个操作 Common 标记的字符串:kCFRunLoopCommonModes (NSRunLoopCommonModes),你可以用这个字符串来操作 Common Items,或标记一个 Mode 为 "Common"。使用时注意区分这个字符串和其他 mode name。
//commonModeItems
//这里使用的模式是:NSRunLoopCommonModes,这个模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的结合。
//运行在此模式下 commonModeItems 内 每当 RunLoop 的内容发生变化时,RunLoop 都会自动将 commonModeItems 里的 Source/Observer/Timer 同步到具有 "Common" 标记的所有Mode里。由于主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为"Common"属性。
//所以NSRunLoopCommonModes此模式会处理 来自UITrackingRunLoopMode和NSDefaultRunLoopMode内的时间
//设置主线程的运行模式为NSRunLoopCommonModes 主线程可以接受来自NSDefaultRunLoopMode和UITrackingRunLoopMode模式下的事件
// [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
NSTimer *timer = nil;
//将 Timer 加入到顶层的 RunLoop 的 "commonModeItems" 中。"commonModeItems" 被 RunLoop 自动更新到所有具有"Common"属性的 Mode 里去。
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
#endif
// NSLog(@"the runloop is %@", [NSRunLoop currentRunLoop]);
[NSThread detachNewThreadSelector:@selector(doSomething) toTarget:self withObject:nil];
}
- (void)doSomething{
_timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerDoSomething) userInfo:nil repeats:YES];
NSLog(@"therad is %@", [NSThread currentThread]);
NSLog(@"doSomething");
NSLog(@"the runloop is %@", [NSRunLoop currentRunLoop]);
// [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
// [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:UITrackingRunLoopMode];
// - (void)run; 无条件运行
// 不建议使用,因为这个接口会导致Run Loop永久性的运行在NSDefaultRunLoopMode模式,即使使用CFRunLoopStop(runloopRef);也无法停止Run Loop的运行,那么这个子线程就无法停止,只能永久运行下去。
// [[NSRunLoop currentRunLoop] run];
/*
如果是使用NSRunLoop,有三个运行的接口:
//1。运行 NSRunLoop,运行模式为默认的NSDefaultRunLoopMode模式,没有超时限制
无法使用CFRunLoopStop(runLoopRef)来停止RunLoop的运行
- (void)run;
//2.运行 NSRunLoop: 参数为运行模式、时间期限,返回值为YES表示是处理事件后返回的,NO表示是超时或者停止运行导致返回的。[Update]: 感谢网友olo的提醒:返回值只有在RunLoop没有运行的情况下才返回NO。比如:1)没有添加输入源和定时器源 2)mode为NSRunLoopCommonModes 或UITrackingRunLoopMode 等“非法”参数。如果超时的话返回YES,即使limitDate的初始值小于当前的Date,RunLoop也会执行一次然后马上返回YES。
- (BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate;
//3.运行 NSRunLoop: 参数为运时间期限,运行模式为默认的NSDefaultRunLoopMode模式
无法使用CFRunLoopStop(runLoopRef)来停止RunLoop的运行
- (void)runUntilDate:(NSDate *)limitDate;
建议是使用第二个接口来运行,因为它能够设置Run Loop的运行参数最多,而且最重要的是可以使用CFRunLoopStop(runLoopRef)来停止Run Loop的运行,而第一个和第三个接口无法使用CFRunLoopStop(runLoopRef)来停止Run Loop的运行。
*/
#if 0
//子线程中 设置 runloop的运行模式 为 NSDefaultRunLoopMode 子线程可以接受来自NSDefaultRunLoopMode模式下的事件
// BOOL isSuccess1 = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//设置子线程的运行模式为NSRunLoopCommonModes 子线程可以接受来自NSDefaultRunLoopMode和UITrackingRunLoopMode模式下的事件 但是对于子线程和主线程有一点不同是,主线程默认已经创建了两个 runloop NSDefaultRunLoopMode和UITrackingRunLoopMode 因此主线程设置 运行在此模式下能直接 接受 NSDefaultRunLoopMode和UITrackingRunLoopMode两个模式的事件,但是由于子线程 的runloop 为空,因此 要先给子线程的runloop添加一个模式上面的[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];及时在给子线程添加一个运行模式。
// BOOL isSuccess = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
//UITrackingRunLoopMode 只能在主线程中使用 子线程中不能使用
BOOL isSuccess = [[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate distantFuture]];
BOOL isSuccess1 = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
NSLog(@"runLoop is %@", isSuccess1 ? @"YES" : @"NO");
NSLog(@"runLoop is %@", isSuccess ? @"YES" : @"NO");
#endif
//对于子线程UITrackingRunLoopMode 参数无效, NSRunLoopCommonModes参数必须在本线程已经被添加过runloop后才有效
// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
// [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
//
// 可以使用CFRunLoopStop(runLoopRef)来停止RunLoop的运行
// CFRunLoopRun();
// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
BOOL ret = 0;
while (_isRuning)
{
// ret = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
// CADisplayLink *ling = [CADisplayLink displayLinkWithTarget:<#(nonnull id)#> selector:<#(nonnull SEL)#>];
// ling addToRunLoop:<#(nonnull NSRunLoop *)#> forMode:<#(nonnull NSString *)#>
//这样写相当于只写了一个while循环 runloop根本没有成功运行 NSRunLoopCommonModes 只对NSTimer和CADisplayLink,NSPort
//NSURLConnection等可以添加到runloop内运行的对象有效,这个NSRunLoopCommonModes是讲这些对象加入到commonItems内,然后将commitItems内
//的发生的事件 发送给 具有 common标记的runloop
//主线程的NSLog(@"runloop is %@", [NSRunLoop currentRunLoop]);
//打印的值为
// common modes = <CFBasicHash 0x7f9db8e012a0 [0x107b28a40]>{type = mutable set, count = 2,
// entries =>
// 0 : <CFString 0x108a5f210 [0x107b28a40]>{contents = "UITrackingRunLoopMode"}
// 2 : <CFString 0x107b495e0 [0x107b28a40]>{contents = "kCFRunLoopDefaultMode"}
// }
// ,
// common mode items = <CFBasicHash 0x7f9db8e014b0 [0x107b28a40]>{type = mutable set, count = 18,
//说明具有common标记的runloop有两个 一个是UITrackingRunLoopMode 一个是kCFRunLoopDefaultMode
//在common mode items 内发生的所有事件都会传递给具有common标记的runloop中 也就是 common mode items 内发生的所有事件都会传递给
//UITrackingRunLoopMode 一个是kCFRunLoopDefaultMode 但是对于主线程的runloop的运行模式 是有主线程负责的
//对于NSRunLoopCommonModes 准确是这个模式是将NSTimer和CADisplayLink,NSPort
//NSURLConnection等 添加到common mode items 内
//对于主线程由于主线程已经具备了两个runloop
NSDefaultRunLoopMode:App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
UIInitializationRunLoopMode:在刚启动App时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
NSRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的Mode
BOOL isRuning = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
NSLog(@"is runing %@", isRuning ? @"YES" : @"NO");
[[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]]
}
NSLog(@"exiting runloop.........: %d", ret);
// [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
// sleep(10);
// [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget:self];
// CFRunLoopStop([NSRunLoop currentRunLoop].getCFRunLoop);
// [[NSRunLoop currentRunLoop] run];
}
- (void)timerDoSomething{
static int i = 0;
i++;
if (i >= 4) {
CFRunLoopStop([NSRunLoop currentRunLoop].getCFRunLoop);
// CFRunLoopStop(CFRunLoopGetCurrent());
_isRuning = NO;
}
NSLog(@"timerDoSomething");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
_isRuning = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
相关文章推荐
- iOS runloop 详解1
- iOS runloop 代码详解1
- iOS runLoop 详解2
- iOS runloop 详解3 如何停止子线程的runloop
- IOS RunLoop详解以及API使用
- iOS开发-Runloop详解(简书)
- iOS runloop 详解3 子线程runloop的启动与停止
- iOS RunLoop详解
- iOS runLoop 用法详解3
- iOS之run loop详解(firecat评:晦涩难懂)
- iOS run loop 详解
- iOS runloop代码详解2
- iOS运行回路(RunLoop)总结
- iOS RunLoop 初识
- iOS关于RunLoop和Timer
- IOS下的 NSTimer与Run loop Modes
- IOS之RunLoop
- iOS Autorelease Runloop
- iOS RUN LOOP 是个什么东西?
- Objective-C之run loop详解