您的位置:首页 > 移动开发 > IOS开发

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: