Grand Central Dispatch(GCD)初探

GCD提供和管理一些先进先出队列,你的应用程序可以以块的形式向这些队列提交任务。提交给队列的块在一个完全由系统维护的线程池上执行。线程对于运行在其上的任务并不作出任何保证。(No guarantee is made as to the thread on which a task executes.

 GCD 提供了三种队列:

  • 主队列 Main: tasks execute serially on your application’s main thread// 任务按照次序在应用的主线程上执行

  • 同步队列 Concurrent: tasks are dequeued in FIFO order, but run concurrently and can finish in any order.// 按先进先出次序出列,同步运行,但完成的次序是随即的。

  • 串行队列 Serial: tasks execute one at a time in FIFO order// 按照先进先出的次序,每次执行一个任务

主队列是系统自动创建的,并且与应用主线程相关联。应用使用下面三个方法中的一个(仅一个)来引用被提交给主队列的块:

使用同步队列来同步执行大量的任务。GCD自动创建了三个同步队列,对应用来说,这三个队列是全局的,而且仅通过它们的优先级来区别。应用通过 dispatch_get_global_queue 函数请求那些队列。因为那些同步队列对于应用来说是全局的,你不需要保持或者释放它们,即使你这样做,也会被忽略掉。在OS X v10.7以上的系统中,你也可以创建额外的同部队列。在你的代码模块中使用。

使用串行队列要保证任务按照一定的顺序执行。为每个串行队列确定一个特定的目的是一个好的习惯,例如保护一个资源或者同步关键过程。应用必须明确地创建和管理串行队列。你可以按需创建串行队列,但是应该避免使用他们替代同步队列,同时执行大量任务。

重要提示:GCD是C语言的API,不处理高层次语言的任何异常,应用应该 在提交给队列的块返回之前,处理所有异常。

目前我主要用的是异步加载PDF文档的页面 , 我的思路是:后台每加载一页,则立即更新对应的UI。两个正确思路如下
1、使用的是dispatch_async、dispath_apply:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 异步操作
    dispatch_async(dispatch_get_main_queue(), ^{
        // UI更新
    });
});
dispatch_apply(num, globalQ, ^(size_t index) {
    // 执行num次,index为当前次数,从0开始计数
});
-(void)LoadPage:(NSInteger)nPage :(NSInteger)num
{
    if (mIsLoading == YES) {
        return;// 正在加载中。。。。。。
    }
    mIsLoading = YES;
    dispatch_queue_t displayQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(displayQueue, ^{
        dispatch_apply(num, displayQueue, ^(size_t index){
            // 执行num次
            NSInteger curPage = nPage + index;
            //NSLog(@"%zu",index);
            NSLog(@"即将加载的页面为:%d",curPage);
            // 加载数据
            sleep(2);
            // 更新页面
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@" 更新页面%d",curPage);
            });// dispatch_get_main_queue
            
        });// dispatch_apply
        mIsLoading = NO;// 加载结束
    });// dispatch_async
}
执行结果如下:

2、该思路使用一个串行队列来处理,具体如下:
if (mIsLoading == YES) {
        return;// 正在加载中。。。。。。
    }
    mIsLoading = YES;
    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);//创建串行队列
    dispatch_async(serialQueue, ^{
        NSLog(@"加载页面 %d!",1);

        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"更新UI 1!");
        });// dispatch_get_main_queue
        
    });// dispatch_async 3
    
    dispatch_async(serialQueue, ^{
        NSLog(@"加载页面 %d!",2);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"更新UI 2!");
        });// dispatch_get_main_queue
        
    });// dispatch_async 3
    
    dispatch_async(serialQueue, ^{
        NSLog(@"加载页面 %d!",3);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"更新UI 3!");
        });// dispatch_get_main_queue
        
    });// dispatch_async 3
    mIsLoading = NO;// 加载结束
运行结果如下:
以前的一些错误思路:
1、
-(void)LoadPage:(NSInteger)nPage
{
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 异步操作
        NSLog(@"即将加载的页面为:%d",nPage);
        // 加载数据
        sleep(2);
        dispatch_async(dispatch_get_main_queue(), ^{
            // UI更新
            NSLog(@" 更新页面%d",nPage);
        });
    });
}
调用的时候,使用循环传入须加载的页码的值。看似正确,实际有很大的安全问题。本质问题就在于,循环是在前台执行,而加载却在后台。
2、
-(void)LoadPage:(NSInteger)nPage :(NSInteger)num
   for (int i = nPage; i< nPage+num; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // 异步操作
            NSLog(@"即将加载的页面为:%d",i);
            // 加载数据
            sleep(2);
            dispatch_async(dispatch_get_main_queue(), ^{
                // UI更新
                NSLog(@" 更新页面%d",i);
            });
        });
    }
}
这种方式跟上一种有异曲同工的错误,看看运行结果吧:

这明显是不正确的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值