RunLoop

  1. 从字面上看是跑圈,运行循环,作用是保持程序的持续运行,处理app中的各种事件,比如触摸事件,定时事件,selector事件,节省cpu资源,提高程序性能,该做事时做事,该休息时休息。其实内部就是一个do while循环,在这个循环内部不断的处理各种事件,比如Source,Timer,Observer等。一个线程对应一个Runloop,主线程runloop默认已经启动,子线程的runloop得手动启动,调用run方法。
    Runloop只能选择一种模式启动,如果当前模式没有 SourceTimerObserver ,那么就退出Runloop。

  2. 其每转一圈,就要检查是否要处理port事件,自定义的source,自定义的selector,定时器等。如果没事情做,就进入休息。一旦有消息发给他,他就跑一圈。

  3. 模式,虽然有多个模式,但只能选择一个模式。这样就只能处理一种模式下的事件。常见的模式有tracking和default模式,当拖拽scrollview时自动切换到tracking模式。当使用common模式时,当未拖拽和拖拽时,定时器自动在default和tracking模式下切换

  4. 当使用 scheduletimer 创建timer时,默认是添加到当前的runloop中,而且是default模式,可以通过[NSRunloop currentRunloop]addTimer:timer forMode:NSRunloopCommonModes] 来修改模式。

  5. loop处理的事件源,CFRunloopSourceRef是事件源,即输入源,根据官方文档,Source的分类,Port-Based Sources 基于端口的源,Custom Input Sources 自定义输入源,Cocoa Perform Selector Sources,按照函数调用栈,source的分类,source0和source1这个仅作为了解。

  6. CFRunloopObserverRef是观察者,能够监听Runloop的状态改变,可以监听的时间点有以下几个:KCFRunloopEntry,即将进入runloop,KCFRunloopBeforeTimers,即将处理Timer,KCFRunloopBeforeSources,即将处理source,KCFRunloopBeforeWaiting,即将进入休眠,KCFRunloopAfterWaiting,刚从休眠中唤醒,KCFRunloopExit,即将退出loop

  7. 添加观察者:监听Runloop的状态

//创建observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(),kCFRunLoopEntry, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity  activity){
});
CFRunloopAddObserver(CFRunloopGetCurrent(),observer,kCFRunloopDefaultMode)
释放Observer
CFRelease(observer)
  1. CF的内存管理(Core Foundation)
    凡是带有Create,Copy,Retain等字眼的函数,创建出来的对象,都需要在最后做一次release,
    release函数:CFRelease(对象)

  2. Runloop里主要有source,observer和timer,点击事件属于source0,

10、如果在拖拽scrollview时同时下载图片可能会出现卡顿,优化方案是使用

[imageview performSelector:@selector(setImage:) withObject:[uiimage imageNamed:@"placeHolder"] afterDelay1.0  inModes:@[NSDefaultRunLoopMode]]

这样是为了使其在默认模式下才下载图片,tracking模式下不下载。

  1. 常驻线程
    正常情况下任务做完线程就死掉了,主线程为什么不死,就是因为主线程里有runloop,runloop里有一个do while循环,
    制作一个常驻线程,可以在线程的方法里添加:
[NSRunloop currentRunloop]addPort:[NSPort port] forMode:NSDefaultRunLoopMode];`
[NSRunloop currentMode]run];

这样这个线程就会成为常驻线程,一直处理这个线程的事件。如果想让这个线程死亡,removePort即可。
一个Runloop包含若干个Mode,每个Mode有包含了若干个Source,Timer,Observer,每次调用Runloop的主函数时,只能指定其中一个Mode。

  1. 子线程里如果创建了定时器,定时器不会启动,一方面是因为定时器没有被添加到runloop里,另一个方面runloop没有启动。子线程的runloop默认没有启动。子线程的runloop和主线程的runloop是单独的两个不同的runloop

  2. 自动释放池的作用,使释放池被释放的时候它里面的所有对象都会调用release方法。
    自动释放池什么时候死?
    当runloop休眠的时候会死,会清理一次,当runloop唤醒的时候又会创建一个自动释放池。

  3. Runloop的使用场景,最常见是创建一个常驻线程,让一个子线程不进入消亡状态,等待其他线程发来的消息,处理其他事件。
    还可以在子线程中开启一个定时器
    在子线程中进行一些长期监控。
    可以控制定时器或行为任务在特定模式下执行
    可以添加oberver监听Runloop的状态,比如监听点击事件的处理

  4. CFRunLoopTimerRef是基于时间的触发器,基本上说的就是NSTimer,它受RunLoop的mode影响,而GCD的定时器不受RunLoop的mode影响。

  5. 很精确的GCD定时器

获得队列
dispatch_queue_t  queue = dispatch_get_global_queue(0,0);

//创建一个定时器,dispatch_source_t本质还是一个oc对象,并且要强引用它
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    //设置定时器的属性(几时开始任务,每隔多长时间执行一次)
    //GCD的时间参数一般是纳秒,1秒 = 10的9次方,NSEC_PER_SEC为纳秒
    //什么时候开始
    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC); //3秒以后开始
    dispatch_source_set_timer(self.timer, start, 3 * NSEC_PER_SEC, 0);
    //设置回调
    dispatch_source_set_event_handler(self.timer, ^{
        
        NSLog(@"当前线程:----%@----",[NSThread currentThread]);
        count++;
        //执行5次以后取消定时器
        if (count == 5)
        {
            dispatch_cancel(self.timer);
            self.timer = nil;
        }
    });
    
    //启动定时器
    dispatch_resume(self.timer);
  1. 当收到内存警告时在appDelegate的receiveMemoryWarning里清除SDWebImage的内存:[[SDWebImageManager sharedManager].imageCache clearMemory],这个是清理内存的,也可以清除沙盒里的图片,imageCache默认的图片的存储时间是7天,也可以设置最大的内存占用的空间大小。clearMemory清除时,正在显示的图片是不会出问题的,因为正在显示的图片有强引用。
    [[SDWebImageManager sharedManager]cancelAll]为取消下载所有正在下载的图片

  2. Gem是一个管理Ruby库和程序的标准包,他通过ruby Gem源来查找,安装,升级和卸载软件包。

  3. 可以通过cocoapods.org网站来查看哪些第三方库支持cocoapods。或者在github上打开一个第三方库,如果这个库的文件里有podspec文件则表示该库支持cocoapod,更新本地的第三方库信息,只需要在终端下输入pod repo update即可,如果在使用pods过程中出现了莫名其妙的问题,可以尝试先把gem升下级:sudo gem update --system ,然后重新安装pod:sudo gem install cocoapods。

  4. runloop的基本作用:

  • 1、保持程序的持续运行
  • 2、处理app中的各种事件(比如触摸事件,定时器事件,Selector事件)
  • 3、节省CPU资源,提高程序性能,该做事时做事,该休息时休息。

21、RunLoop对象:iOS有2套API来访问和使用RunLoop,其中Foundation中用的是NSRunLoop,而Core Foundation中用的是CFRunLoopRef,Core Foundation中的框架均以CF开头,以Ref结尾,NSRunLoop和CFRunLoopRef都代表RunLoop对象。NSRunLoop是基于CFRunLoopRef的一层OC包装所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)

22、RunLoop资料:苹果的官方资料,苹果开源的代码地址:opensource.apple.com。

23、每条线程都有唯一的一个与之对应的RunLoop对象,主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建,RunLoop在第一次访问时创建,在线程结束时销毁,拿到主线程的RunLoop用:[NSRunLoop mainRunLoop],拿到当前线程的RunLoop使用:[NSRunLoop currentRunLoop],如果是CF,则用CFRunloopGetCurrent(),CFRunLoopGetMain(),

24、RunLoop相关类:CFRunLoopRef,CFRunLoopModeRef,CFRunLoopSourceRef,CFRunLoopTimerRef,CFRunLoopObserverRef,RunLoop要想跑起来必须要有Mode,而Mode里必须要有source、timer和observer,RunLoop要想跑起来必须要有Mode,而Mode里必须要有source、timer和observer,RunLoop不断地监听是否有事件发生,如果有则唤醒主线程。

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,启动完成时不再使用,使用完这个后进入defaultMode,这个是苹果在使用。
GSEventReceiveRunLoop:接受系统事件的内部mode,通常用不到,属于系统内部绘图方面的。
KCFRunLoopCommonModes 这是一个占位用的mode,不是一种真正的mode。

25、一个mode里是可以创建多个timer的,是基于时间的触发器,即时间到了就触发一个事件,基本上就是一个NSTimer。定时器只运行在NSDefaultRunLoopMode下,一旦RunLoop进入其他模式,这个定时器就不会工作。

NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self  selector:@selector(run) userInfo:nil  repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode: NSDefaultRunLoopMode];
定时器会跑在标记为common mode的模式下,标记为common modes的模式:UITrackingRunLoopMode和kCFRunLoopDefaultMode
[[NSRunLoop currentRunLoop] addTimer:timer forMode: NSRunLoopCommonModes];

你可能感兴趣的:(RunLoop)