iOS

OC高级-GCD使用总结

2016-08-23  本文已影响3279人  yanhooIT

GCD简介

并行队列 串行队列

// 队列类型
dispatch_queue_t

// 第一个参数:队列名称
// 第二个参数:队列类型
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

/** 队列类型
  // 串行队列标识:本质就是NULL,但建议不要写成NULL,可读性不好
  DISPATCH_QUEUE_SERIAL
  // 并行队列标识
  DISPATCH_QUEUE_CONCURRENT
*/

同步(sync)函数 异步(async)函数

// queue:队列
// block:任务
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
// queue:队列
// block:任务
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

程序猿只需要做下列事情

函数和队列组合后的执行效果

Thread_3.png
- (void)asyncConcurrent
{
    // 1.创建并行队列
//    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2.通过异步函数将将任务加入队列
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"1-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"2-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"3-----%@", [NSThread currentThread]);
        }
    });

    // 证明:异步函数添加任务到队列中,任务【不会】立即执行
    NSLog(@"asyncConcurrent--------end");

    // 释放队列,ARC中无需也不允许调用这个方法
//    dispatch_release(queue);
}
- (void)asyncSerial
{
    // 1.创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
//    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", NULL);

    // 2.通过异步函数将任务加入队列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });

    // 证明:异步函数添加任务到队列中,任务【不会】立马执行
    NSLog(@"asyncConcurrent--------end");
}
- (void)asyncMain
{
    // 1.获得主队列
    dispatch_queue_t queue = dispatch_get_main_queue();

    // 2.通过异步函数将任务加入队列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
}
- (void)syncConcurrent
{
    // 1.获得全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2.通过同步函数将任务加入队列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });

    // 证明:同步函数添加任务到队列中,任务【立马执行】
    NSLog(@"syncConcurrent--------end");
}
- (void)syncMain
{
    // 1.创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);

    // 2.将任务加入队列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
}

GCD实现线程间通信

// 全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 异步函数
dispatch_async(queue, ^
{
        // 执行耗时的任务
        coding...

        // 【标记1】回到主线程,执行UI刷新操作
        dispatch_async(dispatch_get_main_queue(), ^
        {
            coding...

            // 还可以嵌套:再回到子线程做其他事情
            dispatch_async(queue, ^
            {
                coding...
            });
        });

        // 后续代码
        coding....
});

GCD中其他常用函数

dispatch_once_t

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只执行1次的代码(这个函数本身是【线程安全】的)
});

dispatch_after和dispatch_time_t

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC));
dispatch_after(time, queue, ^
{
    // 此任务被延迟提交到队列中
});

dispatch_suspend 和 dispatch_resume

dispatch_apply

dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index)
{
    // 执行10次代码,会开启多条线程来执行任务,执行顺序不确定
});
- (void)applyDemo
{
    NSString *from = @"/Users/xxx/Desktop/From";
    NSString *to = @"/Users/xxx/Desktop/To";

    NSFileManager *mgr = [NSFileManager defaultManager];
    NSArray *subpaths = [mgr subpathsAtPath:from];

    // 并行队列才会起作用
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(subpaths.count, queue, ^(size_t index) {
        NSString *subpath = subpaths[index];
        NSString *fromFullpath = [from stringByAppendingPathComponent:subpath];
        NSString *toFullpath = [to stringByAppendingPathComponent:subpath];
        // 剪切
        [mgr moveItemAtPath:fromFullpath toPath:toFullpath error:nil];

        NSLog(@"%@---%@", [NSThread currentThread], subpath);
    });
}

dispatch_barrier_async

- (void)barrierDemo
{
    //【不能】使用全局并发队列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"----1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----2-----%@", [NSThread currentThread]);
    });

    // 在它前面的任务执行结束后它才执行,在它后面的任务等它执行完成后才会执行
    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"----3-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----4-----%@", [NSThread currentThread]);
    });
}

dispatch_group

// 创建队列组
dispatch_group_t group =  dispatch_group_create();
// 创建队列组
dispatch_group_t group =  dispatch_group_create();

// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 添加任务A到group
dispatch_group_async(group, queue, ^{
    // 添加任务A到group
});

// 添加任务B到group
dispatch_group_async(group, queue, ^{
    // 添加任务B到group
});

// 当任务A和任务B都执行完后到此来执行任务C
dispatch_group_notify(group, queue, ^{
    // 如果这里还有基于上面两个任务的结果继续执行一些代码,建议还是放到子线程中,等代码执行完毕后在回到主线程

    // 回到主线程
    dispatch_async(group, dispatch_get_main_queue(), ^{
        // 执行相关UI显示代码...
    });
});

dispatch_set_context与dispatch_set_finalizer_f的配合使用

// 设置context
void dispatch_set_context(dispatch_object_t object, void *context);

// 获取context
void* dispatch_get_context(dispatch_object_t object);
@interface Data : NSObject

@property(assign, nonatomic) int number;

@end

@implementation Data

// 便于观察对象何时被释放
- (void)dealloc 
{
    NSLog(@"Data dealloc...");
}

@end

-----------------------------------------------------------------------------------------

// 定义队列的finalizer函数,用于释放context内存
void cleanStaff(void *context) {
    // 这里用__bridge转换,不改变内存管理权
    Data *data = (__bridge Data *)(context);
    NSLog(@"In clean, context number: %d", data.number);

    // 释放context的内存!
    CFRelease(context);
}

- (void)testBody 
{
    // 创建队列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);

    // 创建Data类型context数据并初始化
    Data *myData = [Data new];
    myData.number = 10;

    // 绑定context
    // 这里用__bridge_retained将OC对象转换为C对象,将context的内存管理权从ARC移除,交由我们自己手动释放!
    dispatch_set_context(queue, (__bridge_retained void *)(myData));

    // 设置finalizer函数,用于在队列执行完成后释放对应context内存
    dispatch_set_finalizer_f(queue, cleanStaff);

    dispatch_async(queue, ^
   {
        // 获取队列的context数据
        // 这里用__bridge将C对象装换为OC对象转换,并没有改变内存管理权
        Data *data = (__bridge Data *)(dispatch_get_context(queue));
        // 打印
        NSLog(@"1: context number: %d", data.number);
        // 修改context保存的数据
        data.number = 20;
    });
}

参考文章

上一篇下一篇

猜你喜欢

热点阅读