美文网首页
runloop中将一个任务放到第二次runloop中执行

runloop中将一个任务放到第二次runloop中执行

作者: natewang | 来源:发表于2018-06-16 13:17 被阅读9次

runloop中将一个任务放到第二次runloop中执行:利用socket/port做一些事情(封装一个source)

最简单的方法就是

    [self performSelector:@selector(xxxxx) withObject:nil afterDelay:0];

进行了以下的实验

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self observer];
    [self performSelector:@selector(testPerformSelectorAfterDelay) withObject:nil afterDelay:3];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (void)testPerformSelectorAfterDelay {
    
    [self performSelector:@selector(printMyName) withObject:nil afterDelay:0];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"dispatch_after 0");
    });
    
    dispatch_async(dispatch_get_main_queue(),^{
        NSLog(@"dispatch_async 0");
    });
    
    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
        NSLog(@"CFRunLoopPerformBlock 0");
    });
    
    for (int i=0; i < 10; i++) {
        NSLog(@"index is %d", i);
    }
}

- (void)printMyName {
    NSLog(@"performSelector after 0");
}


-(void)observer{
    
    //创建一个监听对象
    /*
     第一个参数:分配存储空间的
     第二个参数:要监听的状态 kCFRunLoopAllActivities 所有状态
     第三个参数:是否要持续监听
     第四个参数:优先级
     第五个参数:回调
     */
    CFRunLoopObserverRef observer =  CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        
        switch (activity) {
            case kCFRunLoopEntry:
                NSLog(@"runloop进入");
                break;
                
            case kCFRunLoopBeforeTimers:
                NSLog(@"runloop要去处理timer");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"runloop要去处理Sources");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"runloop要睡觉了");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"runloop醒来啦");
                break;
                
            case kCFRunLoopExit:
                NSLog(@"runloop退出");
                break;
            default:
                break;
        }
    });
    
    
    //给runloop添加监听者
    /*
     第一个参数:要监听哪个runloop
     第二个参数:监听者
     第三个参数:要监听runloop在哪种运行模式下的状态
     */
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    
//    [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(run1) userInfo:nil repeats:YES];
    
    CFRelease(observer);
}

- (void)run1 {
    
    NSLog(@"run1 run");
}
2018-05-24 12:09:00.671223+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.671392+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.671551+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.671652+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.671801+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.671907+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.672612+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.672976+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.673119+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.674094+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.675117+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.675293+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.675401+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.675769+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.676426+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:00.777952+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:00.780101+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.781568+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.782029+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.782173+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.786887+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.788580+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.791220+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.792284+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.793257+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:00.795218+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:00.796139+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:01.073130+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:01.074644+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:01.075867+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:01.076606+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:02.034410+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:02.035123+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:02.035260+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:02.035395+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:03.646095+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:03.646415+0800 RunLoopDemo[9662:6893911] index is 0
2018-05-24 12:09:03.646521+0800 RunLoopDemo[9662:6893911] index is 1
2018-05-24 12:09:03.646640+0800 RunLoopDemo[9662:6893911] index is 2
2018-05-24 12:09:03.646814+0800 RunLoopDemo[9662:6893911] index is 3
2018-05-24 12:09:03.647089+0800 RunLoopDemo[9662:6893911] index is 4
2018-05-24 12:09:03.647174+0800 RunLoopDemo[9662:6893911] index is 5
2018-05-24 12:09:03.647284+0800 RunLoopDemo[9662:6893911] index is 6
2018-05-24 12:09:03.647372+0800 RunLoopDemo[9662:6893911] index is 7
2018-05-24 12:09:03.647471+0800 RunLoopDemo[9662:6893911] index is 8
2018-05-24 12:09:03.647588+0800 RunLoopDemo[9662:6893911] index is 9
2018-05-24 12:09:03.647673+0800 RunLoopDemo[9662:6893911] CFRunLoopPerformBlock 0
2018-05-24 12:09:03.647824+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:03.647923+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:03.648123+0800 RunLoopDemo[9662:6893911] dispatch_after 0
2018-05-24 12:09:03.648332+0800 RunLoopDemo[9662:6893911] dispatch_async 0
2018-05-24 12:09:03.648635+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:03.648903+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:03.649115+0800 RunLoopDemo[9662:6893911] runloop要睡觉了
2018-05-24 12:09:03.649400+0800 RunLoopDemo[9662:6893911] runloop醒来啦
2018-05-24 12:09:03.649651+0800 RunLoopDemo[9662:6893911] performSelector after 0
2018-05-24 12:09:03.649862+0800 RunLoopDemo[9662:6893911] runloop要去处理timer
2018-05-24 12:09:03.650043+0800 RunLoopDemo[9662:6893911] runloop要去处理Sources
2018-05-24 12:09:03.650312+0800 RunLoopDemo[9662:6893911] runloop要睡觉了

通过log可以发现,只有

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;

会在下一个runloop中调用,GCD的并不一定会在下一个,GCD只是追加到队列中,如果当前runloop没休眠,就会直接运行。

while (true) {
    Call kCFRunLoopBeforeTimers observer callbacks;
    Call kCFRunLoopBeforeSources observer callbacks;
    Perform blocks queued by CFRunLoopPerformBlock;
    Call the callback of each version 0 CFRunLoopSource that has been signalled;
    if (any version 0 source callbacks were called) {
        Perform blocks newly queued by CFRunLoopPerformBlock;
    }
    if (I didn't drain the main queue on the last iteration
        AND the main queue has any blocks waiting)
    {
        while (main queue has blocks) {
            perform the next block on the main queue
        }
    } else {
        Call kCFRunLoopBeforeWaiting observer callbacks;
        Wait for a CFRunLoopSource to be signalled
          OR for a timer to fire
          OR for a block to be added to the main queue;
        Call kCFRunLoopAfterWaiting observer callbacks;
        if (the event was a timer) {
            call CFRunLoopTimer callbacks for timers that should have fired by now
        } else if (event was a block arriving on the main queue) {
            while (main queue has blocks) {
                perform the next block on the main queue
            }
        } else {
            look up the version 1 CFRunLoopSource for the event
            if (I found a version 1 source) {
                call the source's callback
            }
        }
    }
    Perform blocks queued by CFRunLoopPerformBlock;
}

详情见https://stackoverflow.com/a/15168471

YYText监听runloop休眠和退出前去完成一些UI任务。

static void YYRunLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    if (transactionSet.count == 0) return;
    NSSet *currentSet = transactionSet;
    transactionSet = [NSMutableSet new];
    [currentSet enumerateObjectsUsingBlock:^(YYTextTransaction *transaction, BOOL *stop) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [transaction.target performSelector:transaction.selector];
#pragma clang diagnostic pop
    }];
}

static void YYTextTransactionSetup() {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        transactionSet = [NSMutableSet new];
        CFRunLoopRef runloop = CFRunLoopGetMain();
        CFRunLoopObserverRef observer;
        
        observer = CFRunLoopObserverCreate(CFAllocatorGetDefault(),
                                           kCFRunLoopBeforeWaiting | kCFRunLoopExit,
                                           true,      // repeat
                                           0xFFFFFF,  // after CATransaction(2000000)
                                           YYRunLoopObserverCallBack, NULL);
        CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes);
        CFRelease(observer);
    });
}

相关文章

  • runloop中将一个任务放到第二次runloop中执行

    runloop中将一个任务放到第二次runloop中执行:利用socket/port做一些事情(封装一个sourc...

  • RunTime 和 RunLoop 简单总结

    RunLoop 一个线程执行一个任务,执行完成后退出。RunLoop就是执行完之后不退出,重复执行 RunLoop...

  • iOS开发-RunLoop详解

    RunLoop概述 RunLoop是什么?为什么要有RunLoop? 一般来说,一个线程只能执行一个任务,执行完就...

  • iOS开发-RunLoop详解

    RunLoop概述 RunLoop是什么?为什么要有RunLoop?一般来说,一个线程只能执行一个任务,执行完就退...

  • iOS RunLoop概述及应用

    RunLoop概述 RunLoop是什么?为什么要有RunLoop?一般来说,一个线程只能执行一个任务,执行完就退...

  • iOS - RunLoop详解

    RunLoop概述 RunLoop是什么?为什么要有RunLoop?一般来说,一个线程只能执行一个任务,执行完就退...

  • RunLoop

    1、什么是Runloop runloop : 运行循环。一般来说,一个线程一次只能执行一个任务,当执行完任务后线程...

  • 深入理解RunLoop

    RunLoop RunLoop概念 一般来说,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一...

  • RunLoop的事件队列

    RunLoop的事件队列 每次运行RunLoop, 线程中的RunLoop会自动处理线程中的任务, 并且通知观察者...

  • iOS几种常见计时器

    1,最常见的计时器NSTimer (默认放到defaultModel的runloop中,会受到runloop的影响...

网友评论

      本文标题:runloop中将一个任务放到第二次runloop中执行

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