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// 按照先进先出的次序,每次执行一个任务
-
Calling
dispatch_main
-
Calling
UIApplicationMain
(iOS) orNSApplicationMain
(OS X) -
Using a
CFRunLoopRef
on the main thread
使用同步队列来同步执行大量的任务。GCD自动创建了三个同步队列,对应用来说,这三个队列是全局的,而且仅通过它们的优先级来区别。应用通过 dispatch_get_global_queue
函数请求那些队列。因为那些同步队列对于应用来说是全局的,你不需要保持或者释放它们,即使你这样做,也会被忽略掉。在OS X v10.7以上的系统中,你也可以创建额外的同部队列。在你的代码模块中使用。
使用串行队列要保证任务按照一定的顺序执行。为每个串行队列确定一个特定的目的是一个好的习惯,例如保护一个资源或者同步关键过程。应用必须明确地创建和管理串行队列。你可以按需创建串行队列,但是应该避免使用他们替代同步队列,同时执行大量任务。
重要提示:GCD是C语言的API,不处理高层次语言的任何异常,应用应该 在提交给队列的块返回之前,处理所有异常。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;// 加载结束
运行结果如下:
-(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);
});
});
}
调用的时候,使用循环传入须加载的页码的值。看似正确,实际有很大的安全问题。本质问题就在于,循环是在前台执行,而加载却在后台。
-(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);
});
});
}
}
这种方式跟上一种有异曲同工的错误,看看运行结果吧:
这明显是不正确的。