NSRunLoop学习笔记

来源:互联网 发布:淘宝网店服装头像图片 编辑:程序博客网 时间:2024/05/21 10:05

内容是自己学习笔记,来源于互联网

RunLoop简介

基本作用

  1. 保持程序的持续运行,相当于一个do while循环,程序相当于一个死循环,一直在循环内做事情。程序启动时已经启动了一个runLoop,所以程序不会直接退出。是在main函数启动的,和主线程相关.
  2. 处理APP的各种事件:触摸,定时器,selector事件,事件触发的时候,runLoop会按步骤执行事件。
  3. 节省CPU的资源,提升程序性能,合理分配工作和休眠时间,在没有操作任务的时候会进入休眠,有任务到来会唤醒.

runLoop对象

iOS 两套方案访问runLoop

  • Foundation -> NSRunLoop
  • Core Foundation -> CFRunLoopRef

NSRunLoop和CFRunLoopRef都代表RunLoop对象。NSRunLoop是基于CFRunLoopRef的一层OC的包装,CFRunLoopRef是RunLoop底层API.

RunLoop与线程的关系

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

获取RunLoop对象的方法

  • Foundation

     [NSRunLoop mainRunLoop]; [NSRunLoop currentRunLoop];
  • CFRunLoopRef

    CFRunLoopGetCurrent();CFRunLoopGetMain();

RunLoop相关类

CFRunLoopRef ;// CFRunLoopSourceRef;//sourceCFRunLoopTimerRef;//定时器CFRunLoopObserverRef;//观察者CFRunLoopModeRef;//这个类没有外漏

CFRunLoopModeRef

CFRunLoopModeRef表示RunLoop的运行模式.

  1. 一个RunLoop可以包含若干个Mode,一个Mode 包含不同的若干个source,timer,observer。
  2. 每次RunLoop启动只能指定其中一种模式,可以通过curreMode方法获取
  3. 切换mode只能退出Loop,重新再指定一个Mode进入,这样可以分开不同模式下的source,timer,observer

CFRunLoopModeRef以供有5个,其中有两个用不到一个是UIInitializationRunLoopMode 是刚刚进入程序的时候进入的第一个,启动完成后就退出了,还有一个GSEventReceiveRunLoopMode,是系统内部的,也用不到,而且代码根本打不出来,所以可以忽略.

kCFRunLoopCommonModes; //kCFRunLoopDefaultMode|UITrackingRunLoopModekCFRunLoopDefaultMode;//默认模式,app启动后的模式,主线程就是这个模式 UITrackingRunLoopMode;//界面跟踪模式,追踪触屏滑动,保证界面滑动时候不受其他mode影响

CFRunLoopSourceRef

CFRunLoopSourceRef表示的是事件的输入源。

分类1:
- Port-Based Source 基于端口的,内核或者其他线程发过来的信息
- Custom Input Source 自定义的,一般不用
- Cocoa perform selector sources 通过selector消息选择器发送的事件
分类2:
- source0 :非基于port的
- source1 :基于内核的和其他线程通信,接受分发系统事件.

CFRunLoopTimerRef

就是NSTimer,定时器.

CFRunLoopObserverRef

可以监听状态runLoop状态变化的观察者.监听runLoop包含下面的状态

    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {    kCFRunLoopEntry = (1UL << 0),//进入runLoop    kCFRunLoopBeforeTimers = (1UL << 1),//即将处理timer事件    kCFRunLoopBeforeSources = (1UL << 2),//即将处理source    kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入休眠    kCFRunLoopAfterWaiting = (1UL << 6),//刚从休眠中唤醒    kCFRunLoopExit = (1UL << 7),//runLoop退出了    kCFRunLoopAllActivities = 0x0FFFFFFFU//所有的状态};

runLoop处理逻辑

官方版本
这里写图片描述
网络版本
这里写图片描述

runLoop应用

定时器

NSTimer定时器的创建方式
第一种:

    // 调用了scheduledTimer返回的定时器,已经自动被添加到当前runLoop中,而且是NSDefaultRunLoopModeNSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];// 修改模式[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

第二种:创建一个纯净的定时器,需要自己手动设置运行模式

    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];// 定时器只运行在NSDefaultRunLoopMode下,一旦RunLoop进入其他模式,这个定时器就不会工作//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];// 定时器只运行在UITrackingRunLoopMode下,一旦RunLoop进入其他模式,这个定时器就不会工作//    [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];// 定时器会跑在标记为common modes的模式下// 标记为common modes的模式:UITrackingRunLoopMode和NSDefaultRunLoopMode[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

在runLoop状态变化时候做事情

// 创建observer//第一个参数表示如何给observe分配空间,CFAllocatorGetDefault,表示用默认的空间分配器//第二个参数表示监听的是什么状态,可以检测一种也可以检测所有的//YES 表示不是监听一次,而是每次通过这个runLoop的时候都监听//0 位置的参数表示设定优先级,用于多个观察者同时监听一个runLoop的时候,数字越小,优先级越高,默认写0就可以了//后面的块,可以打印相关的状态CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopBeforeWaiting, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {    NSLog(@"----监听到RunLoop状态发生改变---%zd", activity);});// 添加观察者:监听RunLoop的状态//第一个参数.获取添加观察者的runLoop//第二个参数.添加观察者对象//第三个参数.要监听的模式CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);// 释放ObserverCFRelease(observer);

imageView显示

    // 只在NSDefaultRunLoopMode模式下显示图片[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"placeholder"] afterDelay:3.0 inModes:@[NSDefaultRunLoopMode]];

可以解决tableView或者scrollView滑动时候卡顿问题,让图片仅仅在不滑动的时候加载.提升用户体验.

创建不死线程

默认状态下线程执行完操作就死亡了,要创建一个不死线程要用runLoop。
实现策略:
创建一个线程:

    self.thread = [[XMGThread alloc] initWithTarget:self selector:@selector(run) object:nil];[self.thread start];

在线程的run方法里面,添加代码启动新创建的线程的runLoop,
runLoop的run方法,运行的时候如果发现运行模式为空会直接退出,
runLoop不可以没有source,timer,observer.如果3个都没有,就会退出.
所以必须要添加一个保证不退出。

[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];[[NSRunLoop currentRunLoop] run];

调用run方法相当下面的情况的一种,都是一致运行到一个非常大的日期,保证不会退出.创造一个死循环.

// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];//    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];

runLoop循环,不会像do while循环卡死,而是一致在不断的运行着,只有当事件触发的时候才会响应时间,没有事件就会休眠.

0 0
原创粉丝点击