IOS多线程学习八:RunLoop

概述

1.字面意思:运行循环
2.内部实现:内部是由do-while循环实现的

作用

1.保证程序的持续运行
2.处理APP的各种事件(滑动,定时器,selector)
3.节省CPU资源,提高程序性能,让线程有事情做的时候做,没事的时候处于休眠状态。

如果没有RunLoop

以main函数入口为例:

int main(int argc,char *argv[]){
NSLog(@"execute main function");//程序开始
return 0;//程序结束
}

类似于oc程序,执行完相应的代码之后,程序杀死,不能保证APP的持续运行。

如果有RunLoop

以main函数入口为例

int main(int argc, char *argv[]){
do{
     NSLog(@"execute main function");//程序开始
}while(1)
return 0;//程序结束
}
相当于程序内部有一个死循环,保证程序运行不会中断。

main函数中的RunLoop

int main(int argh, char *argv[]){
   @autoreleasepool{
     return UIApplicationMain(argc,argv,nil,NSStringFromClass([AppDelegate class]));
  }
}

在UIApplicationMain函数内部就启动了一个RunLoop,所以UIApplicationMain函数就一直没有返回,保证了程序的持续运行。默认启动的RunLoop是跟主线程相关联的,主要处理与主线程相关的事件。

RunLoop循环图

在这里插入图片描述
线程执行,如果有事件,runloop就提醒线程来处理事件,如果没有事情做,线程处于一个休眠状态直到有操作进入,再提醒线程去做哪些事情,一直处于这种循环中。

RunLoop对象

iOS中有2套API来访问和使用RunLoop

  • Fundation NSRunLoop (OC语言的)
  • Core Foundation CFRunLoopRef (C语言的)
    都代表RunLoop,其间的联系是NSRunLoop是基于CFRunLoopRef。

RunLoop与线程

1.每条线程都有唯一的一个与之对应的RunLoop对象。
2.主线程的RunLoop随着程序已自动创建好,但是子线程的RunLoop需要手动创建。
3.获得主线程的RunLopp的方法是[NSRunLoop mainRunLoop];
4.获得子线程的RunLoop的方法是[NSRunLoop currentRunLoop];
注意:苹果不允许创建RunLoop,只提供了上述两种获得RunLoop的方法。

RunLoop相关类

1.CFRunLoopModeRef
2.CFRunLoopSourceRef
3.CFRunLoopTimeRef
4.CFRunLoopObserverRef
若没有以上几个类,RunLoop是不会循环的。
在这里插入图片描述

CFRunLoopModeRef

1.代表RunLoop的运行模式。
2.一个RunLoop可以包含若干个mode,每个mode包含若干个Source/Timer/Observer
3.每次RunLoop启动时,只能指定其中的一个Mode,这个Mode被称为currentMode
4.如果需要切换Mode,需要退出RunLoop,再重新指定一个Mode进入。这样做的原因是为了分离不同组Source/Timer/Observer,让其互不影响。
系统注册了5个Mode
1.kCFRunLoopDefaultMode:APP默认Mode,通常主线程是在该Mode下运行的
2.UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时,不受其他mode影响
3.UIInitializationRunLoopMode:在刚启动时App进入的第一个Mode,启动完成后就不再使用。
4.GSEventReceiveRunLoopMode:接受系统事件的内部Mode,通常情况下不用。
5.kCFRunLoopCommonMode:这是一个占位的Mode,不是真正的Mode。

CFRunLoopTimerRef

基于时间的触发器,基本可以说是NSTimer。

    //自动加在runloop下,可以直接运行
    // [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
 NSTimer *timer=[NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    //只应用于默认模式下
    //[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
    //只应用于UITrackingRunLoopMode
    //[[NSRunLoop currentRunLoop]addTimer:timer forMode:UITrackingRunLoopMode];
    //应用于2种模式下,commonmodes是模式的标记,有这个标记的模式有UITrackingRunLoopMode, NSDefaultRunLoopMode。    2种模式有共同的标志,只要把这个标志写上,那么2种模式下都能运行。
    [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];

CFRunLoopSourceRef

CFRunLoopSourceRef 是事件源,也可称为输入源。

1.Port-Based Sources 从其他线程或内核发出的。
2.Custom Input Sources自定义的。(很少用到)
3.CoCoa Perform Selector Sources. (常用)

按函数调用栈分类,可分为2类
1.Sources :非基于Port的,常见,比如点击事件
2.Sources1:基于Port的,通过其他线程或者内核通信,接受,分发系统事件。
调用栈其实是栈的一种抽象概念,它表示了方法之间的调用关系。
在这里插入图片描述

    [self performSelector:@selector(run) withObject:nil afterDelay:2 inModes:@[NSRunLoopCommonModes]];

CFRunLoopObserverRef

观察者,能够监听RunLoop的状态的改变。
typedef CF_OPTIONS(CFOptionFlags,CFRunLoopActivity){
kCFRunLoopEntry=(1UL<<0),即将进入RunLoop
kCFRunLoopBeforeTimers=(1UL<<1),//即将处理Timer
kCFRunLoopBeforeSources=(1UL<<2),//即将处理Sources
kCFRunLoopBeforeWaiting=(1UL<<5),//即将进入休眠 2的5次方
kCFRunLoopBeforeAfterWaiting=(1UL<<6),//即将从休眠中唤醒
kCFRunLoopExit=(1UL<<7),即将退出RunLoop
kCFRunLoopAllActivities=0x0FFFFFFFU//活跃中
}
给RunLoop添加观察者,需要CF类

 //如果给runLoop添加观察者,需要CF类
    CFRunLoopObserverRef observer=CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"---%lu---",activity);
    });
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

RunLoop内部逻辑处理

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值