zoukankan      html  css  js  c++  java
  • IOS-NSRunLoop

    一、什么是RunLoop

    基本作用
    保持程序的持续运行
    处理App中的各种事件(比如触摸事件、定时器事件、Selector事件)
    节省CPU资源,提高程序性能:该做事时做事,该休息时休息
     
    main函数中的RunLoop
    UIApplicationMain函数内部就启动了一个RunLoop
    所以UIApplicationMain函数一直没有返回,保持了程序的持续运行
    这个默认启动的RunLoop是跟主线程相关联的
     
    二、RunLoop对象
    1.iOS中有2套API来访问和使用RunLoop
    Foundation
    NSRunLoop
     
    Core Foundation
    CFRunLoopRef
     
    NSRunLoop和CFRunLoopRef都代表着RunLoop对象
    NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)
     
    2.RunLoop资料
    苹果官方文档
     
    lCFRunLoopRef是开源的
     
    3.RunLoop与线程
    每条线程都有唯一的一个与之对应的RunLoop对象
     
    主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
     
    RunLoop在第一次获取时创建,在线程结束时销毁
     
    4.获得RunLoop对象
    Foundation

    [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象

    [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象

    Core Foundation

    CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象

    CFRunLoopGetMain(); // 获得主线程的RunLoop对象

    三、RunLoop相关类

    Core Foundation中关于RunLoop的5个类
    CFRunLoopRef
    CFRunLoopModeRef
    CFRunLoopSourceRef
    CFRunLoopTimerRef
    CFRunLoopObserverRef
     
    1.CFRunLoopModeRef
    CFRunLoopModeRef代表RunLoop的运行模式
    一个 RunLoop 包含若干个 Mode,每个Mode又包含若干个Source/Timer/Observer
     
    每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode
     
    如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入
     
    这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响
     
    系统默认注册了5个Mode:
    kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
     
    UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
     
    UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
     
    GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
     
    kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode
     
    2.CFRunLoopSourceRef
    CFRunLoopSourceRef是事件源(输入源)
     
    以前的分法
    Port-Based Sources
    Custom Input Sources
    Cocoa Perform Selector Sources
     
    现在的分法
    Source0:非基于Port的
    Source1:基于Port的
     
    3.CFRunLoopTimerRef
    CFRunLoopTimerRef是基于时间的触发器
     
    基本上说的就是NSTimer
     
    4.CFRunLoopObserverRef
    CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变
     
    可以监听的时间点有以下几个
     
    四、RunLoop处理逻辑
    官方版
     
     
    网友整理版
     
    五、RunLoop应用
    NSTimer
    ImageView显示
    PerformSelector
    常驻线程
    自动释放池
     
    代码
     1 //
     2 //  ViewController.m
     3 //  IOS_0422_RunLoop
     4 //
     5 //  Created by ma c on 16/4/22.
     6 //  Copyright © 2016年 博文科技. All rights reserved.
     7 //
     8 
     9 #import "ViewController.h"
    10 
    11 @interface ViewController ()
    12 
    13 @end
    14 
    15 @implementation ViewController
    16 
    17 - (void)viewDidLoad {
    18     [super viewDidLoad];
    19     
    20     
    21 }
    22 
    23 - (void)observe
    24 {
    25     //添加observer
    26     CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
    27         NSLog(@"监听到RunLoop状态发生改变");
    28     });
    29     //添加观察者:监听RunLoop状态
    30     CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    31     
    32     CFRelease(observer);
    33 }
    34 - (void)timer
    35 {
    36     NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    37     
    38     //调用scheduledTimer返回的定时器,已经自动添加到当前RunLoop中并且是默认模式
    39     NSTimer *time = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(work) userInfo:nil repeats:YES];
    40     
    41     //定时器只在NSDefaultRunLoopMode下运行,一旦进入其他模式,这个定时器不会工作
    42     [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    43     
    44     //定时器只会跑在NSRunLoopCommonModes模式下
    45     //标记为NSRunLoopCommonModes模式:UITrackingRunLoopMode和kCFDefaultRunLoopMode
    46     [[NSRunLoop currentRunLoop] addTimer:time forMode:NSRunLoopCommonModes]; //修改默认模式
    47 
    48 }
    49 - (void)run
    50 {
    51     NSLog(@"run");
    52 }
    53 
    54 - (void)work
    55 {
    56     NSLog(@"work");
    57 }
    58 @end

    常驻线程

     1 //
     2 //  ViewController.m
     3 //  02-掌握-RunLoop实践
     4 //
     5 //  Created by xiaomage on 15/7/12.
     6 //  Copyright (c) 2015年 小码哥. All rights reserved.
     7 //
     8 
     9 #import "ViewController.h"
    10 #import "XMGThread.h"
    11 
    12 @interface ViewController ()
    13 @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    14 /** 线程对象 */
    15 @property (nonatomic, strong) XMGThread *thread;
    16 @end
    17 
    18 @implementation ViewController
    19 
    20 - (void)viewDidLoad {
    21     [super viewDidLoad];
    22     
    23     self.thread = [[XMGThread alloc] initWithTarget:self selector:@selector(execute) object:nil];
    24     [self.thread start];
    25 }
    26 
    27 /*
    28 - (void)execute
    29 {
    30     NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
    31     [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    32     [[NSRunLoop currentRunLoop] run];
    33 }
    34 
    35 - (void)execute
    36 {
    37     [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
    38 
    39     [[NSRunLoop currentRunLoop] run];
    40 }
    41 */
    42 
    43 //方法3
    44 /*
    45 - (void)execute
    46 {
    47     NSLog(@"----run----%@", [NSThread currentThread]);
    48     
    49     while (1) {
    50         [[NSRunLoop currentRunLoop] run];
    51     }
    52 }
    53 */
    54 
    55 /*
    56 //方法2
    57 //这种方式虽然能保住线程的命,但是这条线程就无法处理其他行为(事件)
    58 - (void)execute
    59 {
    60     NSLog(@"-----run----%@", [NSThread currentThread]);
    61     
    62     while (1); // 当前线程永远在处理这行代码
    63     
    64     NSLog(@"---------");
    65 }
    66 */
    67 
    68 
    69 //方法1-建议使用这种
    70 - (void)execute
    71 {
    72     NSLog(@"----run----%@", [NSThread currentThread]);
    73     
    74     [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    75     [[NSRunLoop currentRunLoop] run];
    76     
    77     NSLog(@"---------");
    78 //    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    79 //    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
    80 }
    81 
    82 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    83 {
    84     [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
    85 }
    86 
    87 - (void)test
    88 {
    89     NSLog(@"-----test----%@", [NSThread currentThread]);
    90 }
    91 
    92 
    93 - (void)useImageView
    94 {
    95     // 只在NSDefaultRunLoopMode模式下显示图片
    96     [self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"placeholder"] afterDelay:3.0 inModes:@[NSDefaultRunLoopMode]];
    97 }
    98 
    99 @end

     GCD定时器

     1 //
     2 //  ViewController.m
     3 //  04-掌握-GCD定时器
     4 //
     5 //  Created by xiaomage on 15/7/12.
     6 //  Copyright (c) 2015年 小码哥. All rights reserved.
     7 //
     8 
     9 #import "ViewController.h"
    10 
    11 @interface ViewController ()
    12 /** 定时器(这里不用带*,因为dispatch_source_t就是个类,内部已经包含了*) */
    13 @property (nonatomic, strong) dispatch_source_t timer;
    14 @end
    15 
    16 @implementation ViewController
    17 
    18 - (void)viewDidLoad {
    19     [super viewDidLoad];
    20     
    21 //    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
    22 //    
    23 //    dispatch_after(when, dispatch_get_main_queue(), ^{
    24 //        NSLog(@"-------");
    25 //    });
    26 }
    27 
    28 int count = 0;
    29 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    30 {
    31     // 获得队列
    32 //    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    33     dispatch_queue_t queue = dispatch_get_main_queue();
    34     
    35     // 创建一个定时器(dispatch_source_t本质还是个OC对象)
    36     self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    37     
    38     // 设置定时器的各种属性(几时开始任务,每隔多长时间执行一次)
    39     // GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)
    40     // 何时开始执行第一个任务
    41     // dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比当前时间晚3秒
    42     dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
    43     uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
    44     dispatch_source_set_timer(self.timer, start, interval, 0);
    45     
    46     // 设置回调
    47     dispatch_source_set_event_handler(self.timer, ^{
    48         NSLog(@"------------%@", [NSThread currentThread]);
    49         count++;
    50         
    51 //        if (count == 4) {
    52 //            // 取消定时器
    53 //            dispatch_cancel(self.timer);
    54 //            self.timer = nil;
    55 //        }
    56     });
    57     
    58     // 启动定时器
    59     dispatch_resume(self.timer);
    60 }
    61 @end
  • 相关阅读:
    C#中 @ 的用法
    ASP.NET页面间传值
    ASP.NET中常用的文件上传下载方法
    把图片转换为字符
    把图片转换为字符
    JavaScript 时间延迟
    Using WSDLs in UCM 11g like you did in 10g
    The Definitive Guide to Stellent Content Server Development
    解决RedHat AS5 RPM安装包依赖问题
    在64位Windows 7上安装Oracle UCM 10gR3
  • 原文地址:https://www.cnblogs.com/oc-bowen/p/5422742.html
Copyright © 2011-2022 走看看