Runloop介绍以及RunLoop的应用场景

南风码哥| 阅读:1227 更新时间:2015-01-09 iOS常用

Runloop注意:一个runloop对应这唯一一条线程,主线程的runloop会自动创建,子线程的的runloop需要手动创建,但是创建的时候只需要获取当前的的runloop对象就可以了(因为他是懒加载的)。1. Runloop基础知识
    1)字面意思
        a 运行循环
        b 跑圈

    2)基本作用(作用重大)
        a 保持程序的持续运行(ios程序为什么能一直活着不会死)
        b 处理app中的各种事件(比如触摸事件、定时器事件(NSTimer)、selector事件(performSelector)
        c 节省CPU资源,提高程序性能,有事情就做事情,没事情就休息

    3)重要说明
        (1)如果没有Runloop,那么程序一启动就会退出,什么事情都做不了。
        (2)如果有了Runloop,那么相当于在内部有一个死循环,能够保证程序的持续运行
        (2)main函数中的Runloop
                a 在UIApplication函数内部就启动了一个Runloop,该函数返回一个int类型的值
                b 这个默认启动的Runloop是跟主线程相关联的

    4)Runloop对象
        (1)在iOS开发中有两套api来访问Runloop
            a.foundation框架【NSRunloop】
            b.core foundation框架【CFRunloopRef】
        (2)NSRunLoop和CFRunLoopRef都代表着RunLoop对象,它们是等价的,可以互相转换
        (3)NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)


    5)Runloop参考资料
        (1)苹果官方文档
        https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
        (2)CFRunLoopRef开源代码下载地址:
        http://opensource.apple.com/source/CF/CF-1151.16/

    6)Runloop与线程
        (1)Runloop和线程的关系:一个Runloop对应着一条唯一的线程
            问题:如何让子线程不死
            回答:给这条子线程开启一个Runloop
        (2)Runloop的创建:主线程Runloop已经创建好了,子线程的runloop需要手动创建
        (3)Runloop的生命周期:在第一次获取时创建,在线程结束时销毁

    7)获得Runloop对象
        (1)获得当前Runloop对象
            //01 NSRunloop
            NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];
            //02 CFRunLoopRef
            CFRunLoopRef runloop2 =   CFRunLoopGetCurrent();

        (2)拿到当前应用程序的主Runloop(主线程对应的Runloop)
            //01 NSRunloop
            NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];
            //02 CFRunLoopRef
            CFRunLoopRef runloop2 =   CFRunLoopGetMain();

        (3)注意点:开一个子线程创建runloop,不是通过alloc init方法创建,而是直接通过调用currentRunLoop方法来创建,它本身是一个懒加载的。
        (4)在子线程中,如果不主动获取Runloop的话,那么子线程内部是不会创建Runloop的。可以下载CFRunloopRef的源码,搜索_CFRunloopGet0,查看代码。

       

(5)Runloop对象是利用字典来进行存储,而且key是对应的线程Value为该线程对应的Runloop。





RunLoop的应用场景

@property

(weak,

nonatomic)

IBOutlet

UIImageView

*imageView;
/**

线程对象*/
@property

(nonatomic

,strong)

NSThread

*thread;
@end

@implementation

ViewController

/*
 1)第一次创建

runloop启动的时候

 2)最后一次销毁

runloop退出的时候

 3)其他时间的创建和销毁
   

当runloop即将休眠的时候会把之前的自动释放池销毁,重新创建一个新的
  _wrapRunLoopWithAutoreleasePoolHandler  activities = 0xa0(160=32+128),activities = 0x1(1)
 */
#pragma mark --------------------
#pragma mark Events
-(void)touchesBegan:(NSSet<UITouch

*> *)touches withEvent:(UIEvent

*)event
{
   
   

/*
     kCFRunLoopEntry = (1UL << 0),              1
     kCFRunLoopBeforeTimers = (1UL << 1),       2
     kCFRunLoopBeforeSources = (1UL << 2),      4
     kCFRunLoopBeforeWaiting = (1UL << 5),      32
     kCFRunLoopAfterWaiting = (1UL << 6),       64
     kCFRunLoopExit = (1UL << 7),               128
     */
//    CFRunLoopActivity

   

NSLog(@"%@",[NSRunLoop

mainRunLoop]);
   

NSLog(@"%d---%d",0x1,0xa0);
   
   

//延迟2秒种设置图片
   

//该方法本身的使用会受到runloop运行模式的影响

默认设定为defaultmode
   

//[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"Snip20200808_1"] afterDelay:2.0];
   
    [self.imageView

performSelector:@selector(setImage:)

withObject:[UIImage

imageNamed:@"Snip20200808_1"]

afterDelay:2.0

inModes:@[NSDefaultRunLoopMode,UITrackingRunLoopMode]];
   
}

#pragma mark --------------------
#pragma mark BtnClick
- (IBAction)createBtnClick:(id)sender
{
   
   

//创建线程
   

NSThread

*thread = [[NSThread

alloc]initWithTarget:self

selector:@selector(task1)

object:nil];
   
   

//开始执行
    [thread

start];
   
   

self.thread

= thread;
}
- (IBAction)goOnBtnClick:(id)sender
{
   
   

//[self.thread start];
   

NSLog(@"--goOn---");
    [self

performSelector:@selector(task2)

onThread:self.thread

withObject:nil

waitUntilDone:YES];
}

#pragma mark --------------------
#pragma mark Events
-(void)task1
{
    

NSLog(@"%s-start--%@",__func__,[NSThread

currentThread]);
   
   

//1.创建子线程对应的runloop
     

NSRunLoop

*runloop = [NSRunLoop

currentRunLoop];
   
   

//2.添加source或者是timer
   
   

/*
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
    [runloop addTimer:timer forMode:NSDefaultRunLoopMode];
     */
   
    [runloop

addPort:[NSPort

port]

forMode:NSDefaultRunLoopMode];
   
   

//3.子线程对应的runloop还需要手动开启
    [runloop

run];
   
   

NSLog(@"%s---%@",__func__,[NSThread

currentThread]);
}

-(void)task2
{
   

NSLog(@"%s---%@",__func__,[NSThread

currentThread]);
}

-(void)timerRun
{
   

NSLog(@"%s---%@",__func__,[NSThread

currentThread]);

}



本文由南风码哥发表并编辑,转载此文章须经作者同意,并请附上出处及本页链接。
取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦