Runloop 运行循环

什么是RunLoop

  • 运行循环
  • 一个线程对应一个RunLoop,主线程的RunLoop默认已经启动,子线程的RunLoop得手动启动(懒加载, 调用currentRunLoop方法)
  • RunLoop只能选择一个Mode启动,如果当前Mode中没有任何Source(Sources0、Sources1)、Timer,那么就直接退出RunLoop

RunLoop作用

  • 保持程序的持续运行
  • 处理App中的各种事件(比如触摸事件、定时器事件、Selector事件)
  • 节省CPU资源,提高程序性能:该做事时做事,该休息时休息 ......

模拟RunLoop内部实现

  • 其实它内部就是do-while循环,在这个循环内部不断地处理各种任务(比如Source、Timer、Observer)
void message(int num)
{
    printf("执行第%i个任务", num);
}
int main(int argc, const char * argv[]) {
    do {
        printf("有事吗? 没事我睡了");
        int number;
        scanf("%i", &number);
        message(number);
    } while (1);
    return 0;
}

获得RunLoop对象

  • RunLoop对象

    • NSRunLoop
    • CFRunLoopRef
  • Foundation(OC) objc [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象,系统会自动创建(懒加载) [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象,主线程默认就有RunLoop
  • Core Foundation(C) objc CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象 CFRunLoopGetMain(); // 获得主线程的RunLoop对象

RunLoop结构

RunLoop相关类

  • Core Foundation中关于RunLoop的5个类:
  • CFRunLoopRef对应RunLoop对象
    • CFRunLoopModeRef代表RunLoop的运行模式, 系统默认注册了5个Mode

      • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
      • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
      • kCFRunLoopCommonModes(NSRunLoopCommonModes) : 这是一个占位用的Mode,不是一种真正的Mode
    • CFRunLoopSourceRef是事件源(输入源)
      • Source0:非基于Port(端口)的
      • Source1:基于Port的
    • CFRunLoopTimerRef是基于时间的触发器
      • CFRunLoopTimerRef基本上说的就是NSTimer,它受RunLoop的Mode影响
    • CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变

// 1.创建Observer
    // 第一个参数:用于分配该observer对象的内存
    // 第二个参数:用以设置该observer所要关注的的事件
    // 第三个参数:用于标识该observer是在第一次进入run loop时执行, 还是每次进入run loop处理时均执行
    // 第四个参数:用于设置该observer的优先级
    // 第五个参数: observer监听到事件时的回调block
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        switch(activity)
        {
            case kCFRunLoopEntry:
                NSLog(@"即将进入loop");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"即将处理timers");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"即将处理sources");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"即将进入休眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"刚从休眠中唤醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"即将退出loop");
                break;
            default:
                break;
        }
    });

    // 2.添加监听
    /*
     第一个参数: 给哪个RunLoop添加监听
     第二个参数: 需要添加的Observer对象
     第三个参数: 在哪种模式下监听
     */
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopDefaultMode);

    // 3,释放observer
    CFRelease(observer);
  • RunLoop处理逻辑

RunLoop应用

  • NSTimer

    • 只能在指定的model下运行 objc NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
  • ImageView显示(一般在默认的模式下设置,所以此方法了解)
    • 只能在指定的model下设置图片 objc [self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"def"] afterDelay:2.0 inModes:@[UITrackingRunLoopMode]];
  • PerformSelector
    • 只能在指定的model下调用 objc [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:[UIImage imageNamed:@"lnj"] waitUntilDone:YES modes:@[NSDefaultRunLoopMode]];

常驻线程

  • 注意点:默认情况下,只要一个线程的任务执行完毕,那么这个线程就不能使用了
  • [NSRunLoop currentRunLoop]仅仅只是创建了一个NSRunLoop对象, 必须调用run才会执行死循环
  • NSRunLoop的model中必须有source/timer,死循环才不会退出
    objc
    NSRunLoop *runloop = [NSRunLoop currentRunLoop];
    [runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    [runloop run];
  • 自动释放池
    • 1: 即将进入RunLoop : 创建一个自动释放池
    • 32:即将休眠 : 释放上一次的自动释放池, 创建一个新的自动释放池
    • 128:即将退出RunLoop : 释放自动释放池
activities = 0x1 = 1
1: 即将进入RunLoop : 创建一个自动释放池
activities = 0xa0 = 160 = 128 + 32
32:即将休眠 : 释放上一次的自动释放池, 创建一个新的自动释放池
128:即将退出RunLoop : 释放自动释放池

RunLoop(运行循环)过程总结:

  • 一个线程对应一个RunLoop,主线程的RunLoop程序启动时默认已经启动
  • 子线程的RunLoop通过查看源码(_CFRunLoopGet0( ))发现是通过字典将线程与RunLoop进行绑定,得手动启动
  • 调用currentRunLoop方法获取子线程的RunLoop,可以理解为懒加载:先判断子线程里有没有RunLoop,有就直接从字典里取,没有就创建并和线程绑定,保存到字典当中
  • RunLoop里有很多的Mode,Mode里又有很多的Source,Timer,Observer,但是只能选择一个Mode启动,这样能防止多个模式的source,timer错乱,不好控制逻辑
  • 如果当前Mode中没有任何Source(Sources0、Sources1)、Timer,那么就直接退出RunLoop
  • 我们可以通过Timer的形式监听RunLoop的执行流程,先进入RunLoop,处理一些系统的事件,执行处理Timer,Source0,Source1...处理完后进入休眠状态
  • 当又有事件时,被唤醒,处理Timer,Source0,Source1...,再进入休眠状态
  • ...
  • RunLoop当Timer超时时会结束,当线程结束时会销毁
时间: 2024-12-25 04:04:15

Runloop 运行循环的相关文章

Runloop(运行循环)是什么?

运行循环是什么?从介绍到演示 今天整理一下运行循环来帮朋友们了解一下什么是运行循环,也叫消息循环,建议大家称之为运行循环(Runloop). 关于多线程的运行循环(消息循环) 1. 什么是运行循环 (1)Runloop就是运行循环,每个线程内部都有一个运行循环. (2)只有主线程的运行循环默认是开启的,子线程的运行循环. 2. 运行循环的作用 (1)保证程序不退出,iOS的应用程序启动之后,之所以不会退出,就是因为有Runloop(运行循环).运行循环是一个死循环,只有满足一定条件才会结束循环.

RunLoop运行循环机制

http://www.jianshu.com/p/0be6be50e461 基本概念 进程 进程是指在系统中正在运行的一个应用程序,而且每个进程之间是独立的,它们都运行在其专用且受保护的内存空间内,比如同时打开迅雷.Xcode,系统就会分别启动两个进程. 线程 一个人进程如果想要执行任务,必须得有至少一条线程,进程的所有任务都会在线程中执行,比如使用网易云音乐播放音乐,使用迅雷下载电影,都需要在线程中执行. 主线程 iOS 程序运行后,系统会默认开启一条线程,称为“主线程”或者“UI 线程”,主

RunLoop(运行循环)-002-加载大图

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "Yuanti SC"; color: #ff2600; background-color: #ffffff } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "Yuanti SC"; color: #008400; background-color: #ffffff } p.p3 { margin:

IOS 开发笔记-基础 UI(9)运行循环的概念

运行循环 int i = 0; // 死循环 while (YES) { printf("请输入一个整数,0表示退出:"); scanf("%d", &i); NSLog(@"%d", i); if (i == 0) { break; } } 以上程序,会不停的循环运行,但是,会在输入的时候中断,等待,有了输入之后,再继续循环运行,且一旦输入了复合条件的值,那么通过 if 判断,break退出循环体. 这就是简单的 runloop 模型.

iOS开发 底层抛析运行循环—— RunLoop

http://blog.csdn.net/zc639143029/article/details/50012527 一.RunLoop基本概念 概念:程序的运行循环,通俗的来说就是跑圈. 1. 基本作用(作用重大) (1) 保持程序的持续运行(ios程序为什么能一直活着不会死) (2) 处理app中的各种事件(比如触摸事件.定时器事件[NSTimer].selector事件[选择器·performSelector···]) (3)节省CPU资源,提高程序性能,有事情就做事情,没事情就休息 2.

运行循环(Run Loops)

运行循环是与线程相关的基础工具的一部分.运行循环是一个用来安排工作并协调传入事件接收的一个事件处理循环.运行循环的目的是当需要工作的时候,让你的线程处于忙碌状态:当没有工作时,让你的线程处于睡眠状态. 运行循环管理并不是完全自动运行,你必须设计线程代码在适当的时间启动运行循环并响应传入的事件.Cocoa和核心基础提供运行循环对象来帮助你配置和管理你的线程运行循环.你的引用不需要显式的创建这些对象,每个线程,包括应用的主线程都有一个关联的运行循环对象.然而,只有次要线程需要显式的运行他们的运行循环

运行循环

程序启动就是有一个运行循环,监听系统中的所有事件 运行有两种模式(从代码来看) NSDefaultRunLoopMode(默认,用户普通点击) NSRunLoopCommonModes(滚动) 一旦发现有滚动事件,默认模式暂时不监听 Timer,(是一个没地位的,) 如果cpu在做大规模运算,cup没时间打理Timer,Timer就闲下来不执行,和下一次一起执行,任务的叠加 Timer,通常用来有一定时间跨度的处理周期性事件,所以不是准确,可以用多线程处理 CADdisplaylink

NSTimer与运行循环

NSTimer准确吗?如果不准确,怎么办? 通常用来有一点时间跨度的周期性事件的处理! CDADisplayLink 1 // 2 // HMViewController.m 3 // 08-倒计时 4 // 5 // Created by apple on 14-8-18. 6 // Copyright (c) 2014年 itcast. All rights reserved. 7 // 8 9 #import "HMViewController.h" 10 11 @interfa

主运行循环

主运行循环负责处理所有跟用户操作相关的事件,主运行循环在程序启动时被 UIApplication 对象创建,运行在主线程上,用来处理事件和更新基于View的UI. 当用户与设备交互时,操作系统生成相关的事件,然后通过一个由 UIKit 创建的端口,交给App.事件先加入事件队列,然后一个一个的交给主运行循环去处理.UIApplication 对象是第一个接收到事件的对象. 大部分类型的事件会交给App.但是有些事件不会,比如加速度计事件会直接交给定义的加速度代理对象去处理. 主运行循环