iOS中有2套API来访问和使用RunLoop,在这篇我想对

2019-11-26 作者:联系我们   |   浏览(154)

IOS RunLoop浅析 三,iosrunloop浅析

经过两篇的介绍我想对RunLoop应该有了简单的了解,至少不至于一无所知。

在这篇我想对“CFRunLoopObserverRef”做一下简单的补充。

在补充之前先说一下。

在现在的开发中已经很少见到ARC了。

但是那是对与OC对象的。

CFRunLoopObserverRef属于CF (Core Foundation)

所以我们需要手动释放。

规则如下:

凡是带有creat copy retain 等成分的函数创建出来的对象都要要在最后进行释放,即Release。

//
//  ViewController.m
//  CX RunLoop浅析
//
//  Created by ma c on 16/3/29.
//  Copyright © 2016年 xubaoaichiyu. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //添加observe
    /* 所监听的状态
     kCFRunLoopEntry = (1UL << 0),
     kCFRunLoopBeforeTimers = (1UL << 1),
     kCFRunLoopBeforeSources = (1UL << 2),
     kCFRunLoopBeforeWaiting = (1UL << 5),
     kCFRunLoopAfterWaiting = (1UL << 6),
     kCFRunLoopExit = (1UL << 7),
     kCFRunLoopAllActivities = 0x0FFFFFFFU
     */
    CFRunLoopObserverRef observe = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {

        NSLog(@"监听到runloop-- %zd",activity);

    });
    //添加观察者
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observe, kCFRunLoopDefaultMode);
    //CF 内存管理 (Core Foundation)
    /*
     凡是带有creat copy retain 等成分的函数创建出来的对象都要要在最后进行释放,即Release。
     */
    CFRelease(observe);
}
@end

上面是对CFRunLoopObserverRef的简单补充。

下面在这里简单介绍一下RunLoop的处理逻辑。

Runloop处理逻辑:

1,通知Observer,即将进入loop

2,通知Observer,将要处理timer

3,通知Observer,将要处理Source0

4,处理Source0

5,如果有Source1,跳到第9步

6,通知Obesrcer,线程即将休眠

7,休眠,等待唤醒

8,通知Observer,线程刚被唤醒

9,处理唤醒时收到的消息,之后跳回2

10,通知Oberver,即将退出Loop

 

RunLoop浅析 三,iosrunloop浅析 经过两篇的介绍我想对RunLoop应该有了简单的了解,至少不至于一无所知。 在这篇我想对CFRunLoopObserverRef做一...

对于runloop的理解不正确的是

A 每一个线程都有其对应的RunLoop
B 默认非主线程的RunLoop是没有运行的
C 在一个单独的线程中没有必要去启用RunLoop
D 可以将NSTimer添加到runloop中
  • 参考答案:C
  • 理由:说到RunLoop,它可是多线程的法定。通常来说,一个线程一次只能执行一个任务,执行完任务后就会退出线程。但是,对于主线程是不能退出的,因此我们需要让主线程即时任务执行完毕,也可以继续等待是接收事件而不退出,那么RunLoop就是关键法宝了。但是非主线程通常来说就是为了执行某一任务的,执行完毕就需要归还资源,因此默认是不运行RunLoop的。NSRunLoop提供了一个添加NSTimer的方法,这个方法是在应用正常状态下会回调。

RunLoop相关类

Core Foundation中关于RunLoop的5个类
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef

Runloop的应用

  • NSTimer
  • ImageView显示
  • PerformSelector
  • 常驻线程
  • 自动释放池

在开发中如何使用RunLoop?什么应用场景?

  • 开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来消息,处理其他事件)

  • 在子线程中开启一个定时器

  • 在子线程中进行一些长期监控

  • 可以控制定时器在特定模式下执行

  • 可以让某些事件(行为、任务)在特定模式下执行

  • 可以添加Observer监听RunLoop的状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)

文章如有问题,请留言,我将及时更正。

满地打滚卖萌求赞,如果本文帮助到你,轻点下方的红心,给作者君增加更新的动力。

runloop定时源和输入源

图片 1

image

  • Runloop处理的输入事件有两种不同的来源:输入源(input source)和定时源(timer source)

  • 输入源传递异步消息,通常来自于其他线程或者程序。

  • 定时源则传递同步消息,在特定时间或者一定的时间间隔发生

NSRunLoop的实现机制,及在多线程中如何使用

- 实现机制:回答runloop的基本作用,处理逻辑,前面都有。

- 程序创建子线程的时候,才需要手动启动runloop。主线程的runloop已经默认启动。

- 在多线程中,你需要判断是否需要runloop。如果需要runloop,那么你要负责配置runloop并启动。你不需要在任何情况下都去启动runloop。比如,你使用线程去处理一个预先定义好的耗时极长的任务时,你就可以无需启动runloop。Runloop只在你要和线程有交互时才需要

请写出NSTimer使用时的注意事项(两项即可)

思路和上一题一样,如果想要销毁timer,则必须先将timer置为失效,否则timer就一直占用内存而不会释放。造成逻辑上的内存泄漏。该泄漏不能用xcode及instruments测出来。 另外对于要求必须销毁timer的逻辑处理,未将timer置为失效,若每次都创建一次,则之前的不能得到释放,则会同时存在多个timer的实例在内存中。
参考答案:
•   注意timer添加到runloop时应该设置为什么mode
•   注意timer在不需要时,一定要调用invalidate方法使定时器失效,否则得不到释放

什么是 Runloop?

  • 从字面上讲就是运行循环。

  • 它内部就是do-while循环,在这个循环内部不断地处理各种任务。

  • 一个线程对应一个RunLoop,主线程的RunLoop默认已经启动,子线程的RunLoop得手动启动(调用run方法)

  • RunLoop只能选择一个Mode启动,如果当前Mode中没有任何Source(Sources0、Sources1)、Timer,那么就直接退出RunLoop

  • 基本的作用就是保持程序的持续运行,处理app中的各种事件。通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。

在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?

  • 思路和上一题一样

为什么 UIScrollView 的滚动会导致 NSTimer 失效?

  • 思路和上一题一样,解决办法有2个,一个是更改mode为NSRunLoopCommonModes(无论runloop运行在哪个mode,都能运行),还有种办法是切换到主线程来更新UI界面的刷新
 //将timer添加到NSDefaultRunLoopMode中
 [NSTimer scheduledTimerWithTimeInterval: target: selector:@selector(timerTick:) userInfo: repeats:];
  //然后再添加到NSRunLoopCommonModes里
   NSTimer *timer = [NSTimer timerWithTimeInterval: target: selector:@selector(timerTick:) userInfo: repeats:];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

CFRunLoopSourceRef

CFRunLoopSourceRef是事件源(输入源)
按照官方文档,Source的分类
Port-Based Sources
Custom Input Sources
Cocoa Perform Selector Sources
按照函数调用栈,Source的分类
Source0:非基于Port的
Source1:基于Port的,通过内核和其他线程通信,接收、分发系统事件

UITableViewCell上有个UILabel,显示NSTimer实现的秒表时间,手指滚动cell过程中,label是否刷新,为什么?

和上一题一样的思路,如果要cell滚动过程中定时器正常回调,UI正常刷新,那么要将timer放入到CommonModes下,因为是NSDefaultRunLoopMode,只有在空闲状态下才会回调。

本文由美高梅赌堵59599发布于联系我们,转载请注明出处:iOS中有2套API来访问和使用RunLoop,在这篇我想对

关键词: