RunLoop
2018-01-30 本文已影响12人
spades_K
含义:运行循环 偏底层
原理: iOS在 UIApplicationMain()中开启,
目的:
1.保证程序不退出。
-
监听事件 触摸、时钟、网络事件。(所有事件跟硬件有关 响应式)
-
如果没有事件发生,让程序进入休眠状态。
//
// ViewController.m
// RunLoop
//
// Created by john on 2018/1/30.
// Copyright © 2018年 john. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
{
dispatch_source_t timer;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)otherMethod
{
NSLog(@"%@",[NSThread currentThread]);
}
- (void)demo1
{
/*
// 封装下面两个 默认模式
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeActiom) userInfo:nil repeats:YES];
*/
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeActiom) userInfo:nil repeats:YES];
// 默认模式 当视图进行拖动时,事件不被调用
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// UI模式只在触摸事件才触发
[[NSRunLoop mainRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
// 占位模式 等于前两个之和的效果
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// timer事件会在UI拖拽过程中是不会执行的
// runLoop模式
/*
1 默认模式 Source Observe Timer 当视图进行拖动时,事件不被调用
2 UI模式 Source Observe Timer 优先级最高 只能被触摸事件所触发
3 占位模式 NSRunLoopCommonModes
*/
}
- (void)demo2
{
// 子线程
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeActiom) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 让runLoop跑起来 死循环 不会再执行下面代码
// currentRunLoop 会调用CFRunloop() 第一次获取runLoop的时候创建RunLoop 懒加载
[[NSRunLoop currentRunLoop] run]; // 跑起来停不了
NSLog(@"来了"); // runLoop没跑起来 对于事件 这个可以打印
// 线程的生命要想保存 只能让它有执行不完的任务。
// while (true) {
// }
}];
[thread start];
}
- (void)demo3
{
NSThread *thred = [[NSThread alloc] initWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
[thred start];
// 线程通讯
[self performSelector:@selector(otherMethod) onThread:thred withObject:nil waitUntilDone:NO]; // 这个 otherMethod方法不会走的 因为线程已经挂掉了 需要线程保活 事件中的通讯是runloop处理的
}
- (void)demo4
{
// GCD实现
//1 创建 timer
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
// 设置 timer 1 秒一次
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0);
// 设置回调
dispatch_source_set_event_handler(timer, ^{
NSLog(@"%@",[NSThread currentThread]);
});
// 启动
dispatch_resume(timer);
/*
Runloop中的source
底层为 CFRunLoopSourceRef
按照函数调用栈分类:
Source0 : 不是Source1的就是Source0
Source1: 内核和其他线程通讯事件。
*/
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 杀掉主线程 程序整体无反应 但是子线程中runLoop还在跑
/*
UI是在主线程上面的
app启动的第一条线程
why 苹果这样设计 ?
A: 安全加效率 UIKIT框架是线程不安全的框架 多线程会出现资源抢夺的情况 安全的话可以加线程锁 但是会出现效率低下的情况 所以苹果这么限制
*/
[NSThread exit];
}
- (void)timeActiom
{
NSLog(@"come l "); // 子线程中runloop不会走这个方法 因为此时线程已经被释放 如果用成员变量对这个线程持有,线程还是会被释放,持有的只是这个对象而已。
// 耗时操作
// [NSThread sleepForTimeInterval:1];
NSLog(@"%@",[NSThread currentThread]);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
参考AF线程保活的方法
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}