iOS 多线程之GCD的使用
在iOS开发中,遇到耗时操作,我们经常用到多线程技术。Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法,只需定义想要执行的任务,然后添加到适当的调度队列(dispatch queue)。GCD会负责创建线程和调度你的任务,系统直接提供线程管理。
一、队列:
基本概念:
1.GCD的一个重要概念是队列,它的核心理念:将长期运行的任务拆分成多个工作单元,并将这些单元添加到dispath queue中,系统会为我们管理这些dispath queue,为我们在多个线程上执行工作单元,我们不需要直接启动和管理后台线程。
2.系统提供了许多预定义的dispath queue,包括可以保证始终在主线程上执行工作的dispath queue。也可以创建自己的dispath queue,而且可以创建任意多个。GCD的dispath queue严格遵循FIFO(先进先出)原则,添加到dispath queue的工作单元将始终按照加入dispath queue的顺序启动。
3.dispatch queue按先进先出的顺序,串行或并发地执行任务
1> serial dispatch queue一次只能执行一个任务, 当前任务完成才开始出列并启动下一个任务
2> concurrent dispatch queue则尽可能多地启动任务并发执行
dispatch queue分成以下三种:
1)运行在主线程的Main queue,通过dispatch_get_main_queue获取。
2)并行队列global dispatch queue,通过dispatch_get_global_queue获取,由系统创建三个不同优先级的dispatch queue。并行队列的执行顺序与其加入队列的顺序相同。
3)串行队列serial queues一般用于按顺序同步访问,可创建任意数量的串行队列,各个串行队列之间是并发的。
当想要任务按照某一个特定的顺序执行时,串行队列是很有用的。串行队列在同一个时间只执行一个任务。我们可以使用串行队列代替锁去保护共享的数据。和锁不同,一个串行队列可以保证任务在一个可预知的顺序下执行。
serial queues通过dispatch_queue_create创建,可以使用函数dispatch_retain和dispatch_release去增加或者减少引用计数。
二、GCD的用法:
// 后台执行:
dispatch_async(dispatch_get_global_queue(, ), ^{
// 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
dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL);
dispatch_async(urls_queue, ^{
// your code
});
dispatch_release(urls_queue); // 合并汇总结果
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(,), ^{
// 并行执行的线程一
});
dispatch_group_async(group, dispatch_get_global_queue(,), ^{
// 并行执行的线程二
});
dispatch_group_notify(group, dispatch_get_global_queue(,), ^{
// 汇总结果
});
三、一个应用GCD的例子:
现在一个耗时操作,从 start working 开始工作,采用多线程,然后把结果显示出来。
声明控件:
@property (weak, nonatomic) IBOutlet UIButton *startButton;
@property (weak, nonatomic) IBOutlet UITextView *resultsTextView;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *spinner;
点击startButton,开始执行。
- (IBAction)doWork:(id)sender
{ NSDate *startTime = [NSDate date]; self.startButton.enabled = NO; [self.spinner startAnimating]; //dispatch_get_global_queue(),抓取一个已经存在并始终可用的全局队列,该函数接受两个参数:第一个指定优先级;第二个目前未使用,应该始终为0.
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ); //将该队列以及它后面的代码块 一起传递给dispatch_async()函数,GCD然后获取整个程序块,并将它传递给一个后台线程,程序块将在这里一次执行一步。
dispatch_async(queue, ^{
NSString *fetchedData = [self fetchSomethingFromServer];
NSString *processedData = [self processData:fetchedData];
__block NSString *firstResult;
__block NSString *secondResult; dispatch_group_t group = dispatch_group_create();
//dispatch_group_async()函数异步分派的所有程序块的设置为松散的,以尽可能快地执行。
dispatch_group_async(group, queue, ^{
firstResult = [self calculateFirstResult:processedData];
});
dispatch_group_async(group, queue, ^{
secondResult = [self calculateSecondResult:processedData];
}); dispatch_group_notify(group, queue, ^{
NSString *resultsSummary = [NSString stringWithFormat:
@"First: [%@]\nSecond: [%@]", firstResult,
secondResult]; //dispatch_get_main_queue函数返回的队列,该函数总是提供线程上的特定队列,并执行需要使用主线程的程序块
dispatch_async(dispatch_get_main_queue(), ^{
self.resultsTextView.text = resultsSummary;
self.startButton.enabled = YES;
[self.spinner stopAnimating]; }); NSDate *endTime = [NSDate date];
NSLog(@"Completed in %f seconds",
[endTime timeIntervalSinceDate:startTime]);
});
});
}
其他方法:
//模拟从服务器获取数据
- (NSString *)fetchSomethingFromServer
{
[NSThread sleepForTimeInterval:];
return @"Hi there";
} - (NSString *)processData:(NSString *)data
{
[NSThread sleepForTimeInterval:];
return [data uppercaseString];
} - (NSString *)calculateFirstResult:(NSString *)data
{
[NSThread sleepForTimeInterval:];
return [NSString stringWithFormat:@"Number of chars: %lu",
(unsigned long)[data length]];
} - (NSString *)calculateSecondResult:(NSString *)data
{
[NSThread sleepForTimeInterval:];
return [data stringByReplacingOccurrencesOfString:@"E"
withString:@"e"];
}
结果显示:

四、GCD的另一个用处是可以让程序在后台较长久的运行。
在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作。但是在使用GCD后,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;
}
iOS 多线程之GCD的使用的更多相关文章
- iOS多线程之GCD小记
iOS多线程之GCD小记 iOS多线程方案简介 从各种资料中了解到,iOS中目前有4套多线程的方案,分别是下列4中: 1.Pthreads 这是一套可以在很多操作系统上通用的多线程API,是基于C语言 ...
- iOS多线程之GCD详解
GCD(Grand Central Dispatch)是基于C语言开发的一套多线程开发机制.也是目前苹果官方推荐的多线程开发方法.iOS三种多线程开发中GCD是抽象层次最高的.当然用起来也是最简单的. ...
- iOS多线程之GCD学习笔记
什么是GCD 1.全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 2.纯C语言,提供了非常多强大的函数 GCD的优势 GCD是苹果公司为多核的并行运算提出的解决方案 G ...
- (五十五)iOS多线程之GCD
GCD的全称为Grand Central Dispatch,翻译为大中央调度,是Apple开发的一个多线程编程解决方法. 进程和线程的概念: 正在进行中的程序被称为进程,负责程序运行的内存分配,每一个 ...
- iOS 多线程之GCD的简单使用
在iOS开发中,遇到耗时操作,我们经常用到多线程技术.Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法,只需定义想要执行的任务,然后添加到适当的调度队列 ...
- ios多线程之GCD
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...
- iOS多线程之GCD、OperationQueue 对比和实践记录
[toc] 简介 在计算的早期,计算机可以执行的最大工作量是由 CPU 的时钟速度决定的.但是随着技术的进步和处理器设计的紧凑化,热量和其他物理约束开始限制处理器的最大时钟速度.因此,芯片制 ...
- IOS 多线程之GCD
参考:http://www.cnblogs.com/wendingding/p/3806821.html <<Objective-C基础教程>> 第二版 一 简介 GCD 全称 ...
- iOS多线程之8.NSOPeration的其他用法
本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...
随机推荐
- 札记:android手势识别,MotionEvent
摘要 本文是手势识别输入事件处理的完整学习记录.内容包括输入事件InputEvent响应方式,触摸事件MotionEvent的概念和使用,触摸事件的动作分类.多点触摸.根据案例和API分析了触摸手势T ...
- OpenCASCADE Shape Location
OpenCASCADE Shape Location eryar@163.com Abstract. The TopLoc package of OpenCASCADE gives resources ...
- 前端学HTTP之实体和编码
前面的话 每天都有各种媒体对象经由HTTP传送,如图像.文本.影片以及软件程序等.HTTP要确保它的报文被正确传送,识别.提取以及适当处理.为了实现这些目标,HTTP使用了完善的标签来描述承载内容的实 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(73)-微信公众平台开发-消息管理
系列目录 前言 回顾上一节,我们熟悉的了解了消息的请求和响应,这一节我们来建立数据库的表,表的设计蛮复杂 你也可以按自己所分析的情形结构来建表 必须非常熟悉表的结果才能运用这张表,这表表的情形涵盖比较 ...
- Ubuntu安装redis并配置远程、密码以及开启php扩展
一.前言 redis是当前流行的nosql数据库,很多网站都用它来做缓存,今天我们来安装并配置下redis 二.安装并配置redis 1.安装redis sudo apt-get install re ...
- maven常见异常以及解决方法
本文写的是我在整合ssm框架时遇到的一些问题,我估计很多人也会遇到,所以,这里作为一个总结,希望能够帮助大家解决问题 一,加入shiro组件时抛出的异常 加入步骤(略) 问题 1,保存后,无法导入sh ...
- thinkphp-无限分类下根据任意部门获取顶级部门ID
根据所得到的部门编号获取顶级部门ID: 参数 - department_id 表格组织架构: tab_departments department_id parent_id name 1 1 顶级 2 ...
- Mono on CentOS 6.3 安装笔记
在网上找到篇关于yum的文章,写的很详细特此推荐下,在阅读本文之前建议先看看它: <CentOS yum源的配置与使用> 如果用的是移动光驱,建议不要开启本地的yum 的本地reposit ...
- 玩转Windows服务系列汇总
玩转Windows服务系列汇总 创建Windows服务 Debug.Release版本的注册和卸载及其原理 无COM接口Windows服务启动失败原因及解决方案 服务运行.停止流程浅析 Windows ...
- 线程笔记:Future模式
线程技术可以让我们的程序同时做多件事情,线程的工作模式有很多,常见的一种模式就是处理网站的并发,今天我来说说线程另一种很常见的模式,这个模式和前端里的ajax类似:浏览器一个主线程执行javascri ...