美文网首页
Observer监听RunLoop状态变化(kCFRunLoop

Observer监听RunLoop状态变化(kCFRunLoop

作者: 飘金 | 来源:发表于2017-06-11 23:46 被阅读0次

要监听RunLoop的状态从NSRunLoop中获取不到任何与Observer相关的信息,更不用说监听了.这时候就需要从CFRunLoopRef入手了.(这边我们监听的是主线程的RunLoop,监听RunLoop的状态变化可以用于优化程序,比如表格要加载大量数据,图片,处理耗时操作,会造成UI卡顿,这时就可以利用监听RunLoop,在他休眠时唤醒它去处理这些任务,例子这边就不举了😘)

点击CFRunLoopRef到API中发现定义了Observer的相关声明CFRunLoopObserverRef,这正是我们想要的😘:

typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoop * CFRunLoopRef;

typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoopSource * CFRunLoopSourceRef;

typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoopObserver * CFRunLoopObserverRef;

typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef;

找到了CFRunLoopObserverRef之后就是要创建一个Observer了,在API中找到如下函数声明:

CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context);

这正是我们想要的创建OBserver的方法😘,看看它需要的参数:

  • CFAllocatorRef allocator 这个鼠标函数的时候Xcode右边解释了一堆(暂时母鸡他的用法)

  • CFOptionFlags activities 表示要监听RunLoop的变化的状态(kCFRunLoopAfterWaiting等)

  • Boolean repeats//表示是否重复监听

  • CFIndex order 这个传0即可暂时没研究

  • CFRunLoopObserverCallBack callout 表示监听的回调方法(C语言的方法)

  • CFRunLoopObserverContext *context 表示上下文环境,用于C语言的方法与OC的互传传值

既然如此现在来创建一个CFRunLoopObserverContext,在API中也找到一个CFRunLoopObserverContext的声明

typedef struct {
    CFIndex version; //暂时传0不研究
    void *  info; //重要就是C语言要与OC传递数据的引用.void *表示可以传递任何类型的数据
    const void *(*retain)(const void *info);//引用
    void    (*release)(const void *info);//回收
    CFStringRef (*copyDescription)(const void *info);//描述,暂时没用
} CFRunLoopObserverContext;

现在创建一个CFRunLoopObserverContext

CFRunLoopObserverContext context =  {
        0,
        (__bridge void *)(self),//OC对象传递过去
        &CFRetain,
        &CFRelease,
        NULL
    };

点击上面的CFRunLoopObserverCallBack是API跳到这样的一个声明,即告诉我们监听的回调方法的参数怎么定义

typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);

接下来新建一个C语言用于回调方法

static void runLoopOserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
   //void *info正是我们要用来与OC传值的,这边可以转成OC对象,前面我们传进来的时候是self
}

到这边万事俱备了😘,可以创建observer了

//创建一个监听
    static CFRunLoopObserverRef observer;
    observer = CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting, YES, 0, &runLoopOserverCallBack,&context);
    //注册监听
    CFRunLoopAddObserver(runLoopRef, observer, kCFRunLoopCommonModes);
    //销毁
    CFRelease(observer);

到此结束😘,完整代码如下:

为了让RunLoop一直工作,这边添加了一个NSTimer,不过他什么都没做,只是为了让RunLoop一直工作

@interface ViewController ()

@property (nonatomic, strong)NSTimer *runLoopObServerTimer;
@property (nonatomic, copy)NSString
 *name;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self addRunLoopObserver];
    [self initData];
}

- (void)initData{
    _name = @"piaojin";
    //默认会添加到当前的runLoop中去,不做任何事情,为了让runLoop一直处理任务而不去睡眠
    _runLoopObServerTimer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
}

- (void)addRunLoopObserver{
    //获取当前的CFRunLoopRef
    CFRunLoopRef runLoopRef = CFRunLoopGetCurrent();
    //创建上下文,用于控制器数据的获取
    CFRunLoopObserverContext context =  {
        0,
        (__bridge void *)(self),//self传递过去
        &CFRetain,
        &CFRelease,
        NULL
    };
    //创建一个监听
    static CFRunLoopObserverRef observer;
    observer = CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting, YES, 0, &runLoopOserverCallBack,&context);
    //注册监听
    CFRunLoopAddObserver(runLoopRef, observer, kCFRunLoopCommonModes);
    //销毁
    CFRelease(observer);
}

//监听CFRunLoopRef回调函数
static void runLoopOserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
    ViewController *viewController = (__bridge ViewController *)(info);//void *info即是我们前面传递的self(ViewController)
    
    NSLog(@"runLoopOserverCallBack -> name = %@",viewController.name);
}

- (void)timerMethod{
    //不做任何事情,为了让runLoop一直处理任务而不去睡眠
}
@end

至此当前的RunLoop一当进入休眠后都会被监听到并且调用runLoopOserverCallBack回调方法

相关文章

  • Observer监听RunLoop状态变化(kCFRunLoop

    要监听RunLoop的状态从NSRunLoop中获取不到任何与Observer相关的信息,更不用说监听了.这时候就...

  • RunLoop -- CFRunLoopObserverRef

    有的时候我们也会自己创建一些Observer去监听RunLoop的状态RunLoop的状态 接下来,监听一下Run...

  • Runloop记录

    流程 添加 Observer 可以监听到 RunLoop 的各种状态 kCFRunLoopEntry: 进入 Ru...

  • 自动释放池

    自动释放池是通过Observer监听RunLoop的状态, 一旦进去睡眠状态(KCFRunLoopBeforeWa...

  • iOS常规的优化技巧

    原文地址 卡顿优化 添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控...

  • 常规优化技巧

    卡顿优化 添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控卡顿的目的...

  • RunLoop 与 AutoreleasePool 的关系

    程序启动后,苹果在主线程 RunLoop 里注册了2个 Observer: 第1个 Observer 监听的事件是...

  • Vue.js数据双向绑定原理(MVVM模式)

    首先需要一个监听器Observer监听数据(model)的变化,具体实现是利用Observer中Object.de...

  • iOS底层-- RunLoop

    手动目录RunLoop 6大响应事件RunLoop 与线程的关系RunLoop状态监听RunLoop 数据结构Ru...

  • CFRunloopObserverRef 的简单介绍

    CFRunloopObserverRef是观察者,能够监听runloop状态的改变。 监听的步骤:1.创建监听者 ...

网友评论

      本文标题:Observer监听RunLoop状态变化(kCFRunLoop

      本文链接:https://www.haomeiwen.com/subject/jppkqxtx.html