RunLoop

# iOS开发之RunLoop

2016-04-11  本文已影响401人  纳萨立克

iOS开发之RunLoop

什么是RunLoop

RunLoop的作用

RunLoop对象

[NSRunLoop currentRunLoop]; //获取当前线程的Runloop
[NSRunLoop mainRunLoop]; //获取主线程的RunLoop
CFRunLoopGetCurrent();//获取当前线程的Runloop
CFRunLoopGetMain(); //获取主线程的RunLoop

RunLoop的机制

CFRunLoopModelRef

代表的是Runloop的运行模式

NSDefaultRunLoopMode 默认状态,空闲状态,通常主线程是在这个Mode下运行
UITrackingRunLoopMode 界面跟踪 Mode, 滑动ScrollView时
UIInitializationRunLoopMode 私有,App启动时进入的第一个Mode 启动完后不在使用
NSRunLoopCommonModes   Mode集合 默认包括上面第一和第二
GSEventReceiveRunLoopMode 接受系统内部时间的Mode

CFRunLoopSource

CFRunLoopTimerRef

CFRunLoopObserver

向外部报告Runloop当前状态的更改,能够监听Runloop的状态的改变

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), //即将进入RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理 Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
    kCFRunLoopBeforeWaiting = (1UL << 5),// 即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
    kCFRunLoopExit = (1UL << 7), //退出
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

    // 创建observer
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"----监听到RunLoop状态发生改变---%zd", activity);
    });

    // 添加观察者:监听RunLoop的状态
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    
    // 释放Observer
    CFRelease(observer);
    

注意这里面的observer是需要释放的: 在ARC中自动内存管理的是OC的对象

CF的内存管理(Core Foundation)

RunLoop的处理逻辑

RunLoopObserver与Autorelease Pool

在RunLoop睡觉之前释放(kCFRunLoopBeforeWaiting)

UITrackingRunLoopMode 与 Timer

Timer默认是被添加在NSDefaultRunLoopMode中的,当ScrollerView滑动的时候就会影响到
Timer,若不希望Timer被影响,需要添加到NSRunLoopCommonModes

    
    [[NSRunLoop currentRunLoop] addTimer:[NSTimer timerWithTimeInterval:1 target:self selector:@selector(timeaction) userInfo:nil repeats:NO] forMode:NSRunLoopCommonModes];
    

Runloop与dispath_get_main_queue()

GCD到dispath到main queque的block被分发到main Runloop执行

GCD中的定时器和Runloop没有关系的,GCD的定时器是不受RunLoop的Mode的影响的

    // 获得队列
//    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 创建一个定时器(dispatch_source_t本质还是个OC对象)
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    // 设置定时器的各种属性(什么时候开始任务,每隔多长时间执行一次)
    // GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)
    // 何时开始执行第一个任务
    // dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比当前时间晚3秒
    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
    uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
    dispatch_source_set_timer(self.timer, start, interval, 0);
    
    // 设置回调
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"------------%@", [NSThread currentThread]);
        count++;
        
//        if (count == 4) {
//            // 取消定时器
//            dispatch_cancel(self.timer);
//            self.timer = nil;
//        }
    });
    
    // 启动定时器
    dispatch_resume(self.timer);

RunLoop的挂起与唤醒

     //在子线程中默认是没有RunLoop的 
    //获取Runloop,当当前线程没有runloop的时候,该方法就会启动runloop
    NSRunLoop *loop = [NSRunLoop currentRunLoop];
    
    //给Runloop一个端口,这样就可以保持Runloop处于唤醒的状态
    [loop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];

    //run
    [loop run];

RunLoop创建一个常驻服务线程的方法

 [[NSThread currentThread] setName:@"thread1"];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefalutRunLoopMode]//一直活着
[runLoop run];

Topic: 一个TableView延迟加载图片的思路

    UIImageView * iconImageView = [UIImageView new];

    UIImage *image = nil;
    
    [iconImageView performSelector:@selector(setImage:) withObject:image afterDelay:0 inModes:@[NSDefaultRunLoopMode]];
    
    //NSDefaultRunLoopMode 设置为这个模式的时候 当TableView在滑动到时候Runloop在UITrackingRunLoopMode模式,这样setimage方法就不会被调用.只有不滑动的时候,runloop切换到NSDefaultRunLoopMode模式,这时候设置图片
    

应用场景

上一篇下一篇

猜你喜欢

热点阅读