GCD/Block

作者: 码农小白 | 来源:发表于2017-07-21 16:07 被阅读23次

    GCD

    唐巧的博客

    block 的定义

    block 的定义有点象函数指针,差别是用 ^ 替代了函数指针的 * 号,如下所示:

    // 申明变量
    (void) (^loggerBlock)(void);
    
    // 定义
    loggerBlock = ^{ 
       NSLog(@"Hello world");
    };
    
    // 调用
    loggerBlock();
    

    但是大多数时候,我们通常使用内联的方式来定义 block,即将它的程序块写在调用的函数里面,例如这样:

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
         // something
    });
    

    从上面大家可以看出,block 有如下特点:

    • 程序块可以在代码中以内联的方式来定义。
    • 程序块可以访问在创建它的范围内的可用的变量。

    系统提供的 dispatch 方法

    为了方便地使用 GCD,苹果提供了一些方法方便我们将 block 放在主线程 或 后台线程执行,或者延后执行。使用的例子如下:

    //  后台执行:
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
         // something
    });
    // 主线程执行:
    dispatch_async(dispatch_get_main_queue(), ^{
         // something
    });
    // 一次性执行:
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // code to be executed once
    });
    // 延迟 2 秒执行:
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        // code to be executed on the main queue after delay
    });
    

    dispatch_queue_t 也可以自己定义,如要要自定义 queue,可以用 dispatch_queue_create 方法,示例如下:

    dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL);
    dispatch_async(urls_queue, ^{
         // your code
    });
    dispatch_release(urls_queue);
    

    另外,GCD 还有一些高级用法,例如让后台 2 个线程并行执行,然后等 2 个线程都结束后,再汇总执行结果。这个可以用 dispatch_group, dispatch_group_async 和 dispatch_group_notify 来实现,示例如下:

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
         // 并行执行的线程一
    });
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
         // 并行执行的线程二
    });
    dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
         // 汇总结果
    });
    

    修改 block 之外的变量

    默认情况下,在程序块中访问的外部变量是复制过去的,即写操作不对原变量生效。但是你可以加上 __block 来让其写操作生效,示例代码如下:

    __block int a = 0;
    void  (^foo)(void) = ^{
         a = 1;
    }
    foo();
    // 这里,a 的值被修改为 1
    

    后台运行

    使用 block 的另一个用处是可以让程序在后台较长久的运行。在以前,当 app 被按 home 键退出后,app 仅有最多 5 秒钟的时候做一些保存或清理资源的工作。但是应用可以调用 UIApplicationbeginBackgroundTaskWithExpirationHandler方法,让 app 最多有 10 分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。

    让程序在后台长久运行的示例代码如下:

    // AppDelegate.h 文件
    @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;
    // AppDelegate.m 文件
    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
        [self beingBackgroundUpdateTask];
        // 在这里加上你需要长久运行的代码
        [self endBackgroundUpdateTask];
    }
    - (void)beingBackgroundUpdateTask
    {
        self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
            [self endBackgroundUpdateTask];
        }];
    }
    - (void)endBackgroundUpdateTask
    {
        [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
        self.backgroundUpdateTask = UIBackgroundTaskInvalid;
    }
    

    相关文章

      网友评论

          本文标题:GCD/Block

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