频道栏目
首页 > 资讯 > IOS > 正文

iOS 多线程编程(十五、RunLoop简单介绍)

16-11-03        来源:[db:作者]  
收藏   我要投稿

一:什么是RunLoop

(1)从字面意思看,运行循环、跑圈。
(2)保持程序持续运行,处理App中的各类事件包括触摸事件、定时器事件、Selector事件。
(3)节省CPU资源,提高程序的性能,该做事的时候做事,该休息的时候休息。

二:RunLoop与线程

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

三:RunLoop相关类

Core Foundation中关于RunLoop的5个类
1:CFRunLoopRef
2:CFRunLoopModeRef ,CFRunLoopModeRef代表RunLoop的运行模式,一个RunLoop包含若干个运行模式,即一个RunLoop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer,每次RunLoop启动时,只能指定其中一个Mode,这个Mode被称作CurrentMode,如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入。系统默认注册了5个Mode:
(1)kCFRunLoopDefaultMode:App的默认的Mode,通常线程是在这个Mode下运行
(2)UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其它Mode影响
(3)UIInitializationRunLoopMode:在刚启动App时进入的第一个Mode,启动完成后就不再使用
(4)GSEventReceiveRunLoopMode:接收系统事件的内部Mode,通常用不到。
(5)kCFRunLoopCommonMode:这是一种占位用的Mode,不是一种真正的Mode。
3:CFRunLoopTimerRef
(1)CFRunLoopTimerRef是基于时间的触发器。
(2)基本上说的就是NSTimer,它会受到runloop的Mode的影响。
(3)GCD的定时器不受RunLoop的mode的影响。
关于定时器和runloopMode的关系如下代码
//
//  ViewController.m
//  CFRunLoopTimerRef
//
//  Created by fe on 2016/10/25.
//  Copyright © 2016年 fe. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic , strong) dispatch_source_t timer;
@end

@implementation ViewController

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    
    [self GCDTimer];

}


-(void)timer1
{
    /*
     第一种定时器用法,这种方式创建的定时器,
     系统默认添加到NSRunLoop中的NSDefaultRunLoopMode模式中,
     但是当用户和应用交互发生触摸滑动等事件时,
     RunLoop的模式会切换到UITrackingRunLoopMode,
     此时定时器就不再工作,因为定时器只在,默认被添加到的NSDefaultRunLoopMode
     模式下工作。
     */
    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(go) userInfo:nil repeats:YES];
}
-(void)timer2
{
    /*
     第二种定时器用法,这种方式创建的定时器,如果添加到NSRunLoop,
     并设置RunLoop模式为NSDefaultRunLoopMode,
     当用户和应用交互发生触摸滑动等事件时,
     RunLoop的模式会切换到UITrackingRunLoopMode,
     此时定时器就不再工作,因为定时器只在NSDefaultRunLoopMode模式下工作。
     
     如果把用这种方式创建的定时器,添加到NSRunLoop,
     并设置RunLoop模式为UITrackingRunLoopMode,
     在这种情况下,只有当用户和应用交互发生触摸滑动等事件时,
     定时器才会工作。
     
     为了解决以上两种RunLoop运行模式造成的定时器,定时不准的问题。
     我们可以把定时器添加到RunLoop并设置运行模式为NSRunLoopCommonModes.
     在这种运行模式下,不管是默认状态,还是当用户和应用交互发生触摸滑动等事件时。
     定时器都可以正常工作。
     */
    //1:创建定时器
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(go) userInfo:nil repeats:YES];
    
    //2.1:把定时器添加到RunLoop中,定时器在NSDefaultRunLoopMode模式下工作。
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    
    //2.2:把定时器添加到RunLoop中,定时器在UITrackingRunLoopMode模式下工作。
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
    //2.3
    /*
     把定时器添加到RunLoop中,设置模式为NSRunLoopCommonModes,
     定时器在UITrackingRunLoopMode模式和NSDefaultRunLoopMode模式下都工作。
     
     NSRunLoopCommonModes是一种标记模式,被打上这种标记的模式有以下两种
     0 : contents = "UITrackingRunLoopMode"
     2 : contents = "kCFRunLoopDefaultMode"
     */
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    NSLog(@"---------%@",[NSRunLoop currentRunLoop]);
    

}
-(void)GCDTimer
{
    /*
     使用GCD的定时器,不会受到RunloopMode的影响。
     */
    
    
    //0:创建队列
    dispatch_queue_t queue = dispatch_queue_create("cn.520.www", DISPATCH_QUEUE_CONCURRENT);
    
    //1:创建一个GCD定时器
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    self.timer = timer;
    
    //2:设置定时器的开始时间,间隔时间,精确度。精准度一般填0,表示没有误差。
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    
    //3:定时器要调用的方法。
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"----------%@",[NSThread currentThread]);
    });
    
    //4:启动定时器。
    dispatch_resume(timer);
}
-(void)go
{
    NSLog(@"-----------");
}
@end

 
4:CFRunLoopSourceRef
(1)CFRunLoopSourceRef是事件源(输入源),分为两种。
(2)Source0:非基于Port的,用于用户主动触发的事件。
(3)Source1:基于Port的,通过内核和其它线程相互发送消息。
5:CFRunLoopObserverRef
(1)CFRunLoopObserverRef是观察者,能够监听RunLoop状态的改变。
(2)可以监听的时间点有一下几个
/* Run Loop Observer Activities */
    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
        kCFRunLoopEntry = (1UL << 0),//即将进入loop
        kCFRunLoopBeforeTimers = (1UL << 1),//即将处理timer
        kCFRunLoopBeforeSources = (1UL << 2),//即将处理Source
        kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入休眠
        kCFRunLoopAfterWaiting = (1UL << 6),//即将从休眠中唤醒
        kCFRunLoopExit = (1UL << 7),//即将推出RunLoop
        kCFRunLoopAllActivities = 0x0FFFFFFFU//监听所有状态
    };
和CFRunLoopObserverRef相关的代码如下:
-(void)observer
{
    /*
     第一个参数:开辟内存空间
     第二个参数:监听runloop的什么事件
     第三个参数:是否持续监听
     第四个参数:优先级
     第五个参数:回掉
     */
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        
        switch (activity){
           case kCFRunLoopEntry:
                NSLog(@"--runloop即将进入循环--");
                break;
                
            case kCFRunLoopBeforeTimers:
                NSLog(@"--runloop将要处理timer--");
                break;
                
            case kCFRunLoopBeforeSources:
                NSLog(@"--runloop将要处理sources--");
                break;
                
            case kCFRunLoopBeforeWaiting:
                NSLog(@"--runloop将要进入休眠--");
                break;
                
            case kCFRunLoopAfterWaiting:
                NSLog(@"--runloop休眠结束即将进入循环--");
                break;
                
            case kCFRunLoopExit:
                NSLog(@"--runloop退出循环--");
                break;
                
            default:
                break;
        }
    
    });
    
    
    
    /*
     第一个参数:要监听哪一个runloop
     第二个参数:监听者
     第三个参数:要监听runloop在哪种运行模式下的状态
     */
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

   
}


 
 
 
 
 
 
相关TAG标签
上一篇:Android群英传--动画机制与技巧(一)
下一篇:Java设计模式之——状态模式
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站