ios开发指南实战项目开发iOS开发

RunLoop

2016-12-26  本文已影响13人  阿凡提说AI

一、简介

RunLoop的字面意思就是运行循环,跑圈。
基本作用:

屏幕快照 2016-12-26 下午11.06.05.png
第14行代码的UIApplicationMain函数内部就启动了一个RunLoop

所以UIApplicationMain函数一直没有返回,保持了程序的持续运行

这个默认启动的RunLoop是跟主线程相关联的

二、RunLoop对象

1.RunLoop对象
iOS中有2套API来访问和使用RunLoop

一种Foundation,NSRunLoop
一种是CoreFoundation,CFRunLoopRef

NSRunLoop和CFRunLoopRef都代表着RunLoop对象
NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)
2.RunLoop与线程

每条线程都有唯一的一个与之对应的RunLoop对象
主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
RunLoop在第一次获取时创建,在线程结束时销毁

3.获得RunLoop对象

// 获得当前线程的RunLoop对象
[NSRunLoop currentRunLoop];  
// 获得主线程的RunLoop对象
[NSRunLoop mainRunLoop];      
// 获得当前线程的RunLoop对象
CFRunLoopGetCurrent();

// 获得主线程的RunLoop对象
CFRunLoopGetMain();

三、RunLoop相关类

CoreFoundation中关于RunLoop的5个类

CFRunLoopRef

CFRunLoopModeRef

CFRunLoopSourceRef

CFRunLoopTimerRef

CFRunLoopObserverRef

1、CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变

// 创建observer
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"----监听到RunLoop状态发生改变---%zd", activity);
    });

    // 添加观察者:监听RunLoop的状态
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    
    // 释放Observer
    CFRelease(observer);

2.CFRunLoopTimerRef是基于时间的触发器,基本上说的就是NSTimer.
3.CFRunLoopModeRef

CFRunLoopModeRef代表RunLoop的运行模式
一个 RunLoop包含若干个 Mode,每个Mode又包含若干个Source/Timer/Observer
每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode
如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入
这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响
屏幕快照 2017-01-12 上午9.12.45.png

4.CFRunLoopSourceRef是事件源(输入源)
Source0:非基于Port的
Source1:基于Port的

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.thread = [[XMGThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [self.thread start];
}


- (void)run
{
    NSLog(@"----------run----%@", [NSThread currentThread]);
    
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
    
    NSLog(@"---------");
//    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
//    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
}


四、RunLoop的处理逻辑

007A4CE9-5050-4366-BA12-2F0D189DDEE4.png 6AF9977F-E0EC-4F9A-97E9-5B1B75375ADF.png

五、GCD定时器

#import "ViewController.h"

@interface ViewController ()
/** 定时器(这里不用带*,因为dispatch_source_t就是个类,内部已经包含了*) */
@property (nonatomic, strong) dispatch_source_t timer;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
//    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
//    
//    dispatch_after(when, dispatch_get_main_queue(), ^{
//        NSLog(@"-------");
//    });
}

int count = 0;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 获得队列
//    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 创建一个定时器(dispatch_source_t本质还是个OC对象)
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    // 设置定时器的各种属性(几时开始任务,每隔多长时间执行一次)
    // GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)
    // 何时开始执行第一个任务
    // dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比当前时间晚3秒
    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
    uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
    dispatch_source_set_timer(self.timer, start, interval, 0);
    
    // 设置回调
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"------------%@", [NSThread currentThread]);
        count++;
        
//        if (count == 4) {
//            // 取消定时器
//            dispatch_cancel(self.timer);
//            self.timer = nil;
//        }
    });
    
    // 启动定时器
    dispatch_resume(self.timer);
}
@end

上一篇下一篇

猜你喜欢

热点阅读