block 备忘录

2016-08-12  本文已影响26人  芙箩娅

引子

半夜突然想写点什么,又不想填之前的坑……因为懒,然后就想到了这个,感觉这应该算是block相关技巧,就根据缺总的提示做了一个测试,顺便再挖下一个大坑,以后遇到有block相关的问题就更新在这里

不知不觉中好像又挖了一个大坑…….png

挖坑这种事嘛,填不填不重要…重要的是要经常挖…

1. block 异步操作执行顺序相关

起因是这个:

66AEA76053CB8DD66B46656F62D1B642.jpg B0F7BE74AFA0E28362230A39764C1283.jpg

代码是这样:

0039E5D0D402D4467FA0468E5F58A546.jpg

简单的说就是将某个耗时任务塞进队列,必须等到该耗时任务完成后判断某个返回值的状态,然后在主线程中更改预设的BOOL返回值。

但是实际操作中却出现了获取返回值总是先一步于异步线程(block)执行完毕,相当于做了无用功。

打开xcode 随便添加了一个按钮及对应的方法,照着缺总的提示写了一下

1 . 模拟假想情况

- (void)test1 {
    NSLog(@"开始测试——————Step.1");
    __block BOOL isDone = NO;
    dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(defaultQueue, ^{
        for (int i = 0; i < 1000000; i++) {
            if (i == 999999) {
                NSLog(@"循环结束——————Step.2");
                isDone = YES;
            }
        }
    });
    NSLog(@"执行完毕——————Step.3");
}

测试结果

85988E6F-DB08-4BDD-B11F-B7CA217FE50A.png

预料中的结果,耗时操作在 执行完毕后才显示出来

2 . 模拟出现问题的环境……

- (void)test2 {
    NSLog(@"开始测试——————Step.1");
    __block BOOL isDone = NO;
    dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(defaultQueue, ^{
        for (int i = 0; i < 1000000; i++) {
            if (i == 999999) {
                 NSLog(@"循环结束——————Step.2");
                isDone = YES;
            }
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            if (isDone == YES) {
                NSLog(@"执行完毕——————Step.3");
            }
        });
    });
    NSLog(@"不能判断BOOL值是否已经改变----Step.4");
}

执行结果

23469DFB-F725-4523-B18A-7B58C1D70AD5.png

应该就是差不多就是这个样子,尽管在队列里面添加了get_main_queue事件,step.2 step3 也是按照顺序执行了,但是step.4 仍然先一步于异步任务之前执行了。如果说接下来的需要执行的任务塞在step3那个位置不合适的话,那就有些蛋疼了。

3 . **正确的 体位 打开方式 **

- (void)test3 {
    NSLog(@"开始测试——————Step.1");
    __block BOOL isDone = NO;
    dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(defaultQueue, ^{
        for (int i = 0; i < 1000000; i++) {
            if (i == 999999) {
                NSLog(@"循环结束——————Step.2");
                
            }
        }
        isDone = YES;
        NSLog(@"执行完毕——————Step.3");
    });
    while (!isDone) {
        NSDate *date = [NSDate distantFuture];
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
         NSLog(@"唤醒线程");
    }
    NSLog(@"Next To Do----Step.4");
    NSLog(@"%d",isDone);
}

执行结果

D7646AD9-1ECF-45E8-A009-3A1EE7675AC7.png

算是达到需要的效果了

核心思想是 通过runLoop 让封装的block所在线程休眠,而其结果的判断回调会将其唤醒,然后才执行下一步。

唉.png

话说 NSDate *date = [NSDate distantFuture]; 我楞了好久…看着好眼熟,就是想不起来干嘛用的…


我为什么那么喜欢挖坑呢……


8月

逛博客的时候突然看到runloop的一篇文章

1.只有在为你的程序创建次线程的时候,才需要运行run loop。对于程序的主线程而言,run loop是关键部分。Cocoa提供了运行主线程run loop的代码同时也会自动运行run loop。IOS程序UIApplication中的run方法在程序正常启动的时候就会启动run loop。如果你使用xcode提供的模板创建的程序,那你永远不需要自己去启动run loop

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

配合上面测试的东西有了一点点顿悟的感觉 ,果然还是要结合实际情况,如果光是单纯的这么一段文字我也许看过就忘了。

感觉总结的很好,正是因为与线程发生了交互,才需要对runloop进行一定的操作。

上一篇下一篇

猜你喜欢

热点阅读