iOS开发之多线程技术(NSThread、OperationQueue、GCD)
在前面的博客中如果用到了异步请求的话,也是用到的第三方的东西,没有正儿八经的用过iOS中多线程的东西。其实多线程的东西还是蛮重要的,如果对于之前学过操作系统的小伙伴来说,理解多线程的东西还是比较容易的,今天就做一个小的demo来详细的了解一下iOS中的多线程的东西。可能下面的东西会比较枯燥,但还是比较实用的。
多线程用的还是比较多的,废话少说了,下面的两张截图是今天我们实验的最终结果,应该是比较全的,小伙伴们由图来分析具体的功能吧:

功能说明:
1、点击同步请求图片,观察整个UI界面的变化,并点击测试按钮,红色是否会变成绿色。
2、NSThread按钮,是由NSThread方式创建线程并执行相应的操作。
3、Block操作按钮是用Block创建操作,并在操作队列中执行,下面的是Invocation操作
4、serial是GCD中的串行队列,concurrent是GCD中的并行队列
好啦,上面的咸蛋先到这儿,代码该走起啦。
一、准备阶段
1.不管使用代码写,还是storyboard或者xib等,先把上面所需的控件初始化好以便使用
2.点击测试UI按钮,改变下边label的颜色的代码如下:
//改变lable的颜色,在红绿颜色之间进行交换
- (IBAction)tapTestButton:(id)sender {
static int i = ;
if (i == ) {
_testLabel.backgroundColor = [UIColor redColor];
i = ;
}
else
{
_testLabel.backgroundColor = [UIColor greenColor];
i = ;
} }
3.从网络上获取图片,并使用主线程显示进程调用情况
//从wang'lu获取图片数据
-(NSData *) getImageData
{ _count ++;
int count = _count;
//线程开始启动
7 NSString *str = [NSString stringWithFormat:@"%d.线程%@",count,[NSThread currentThread]];
NSLog(@"%@",str);
NSData *data;
[NSThread sleepForTimeInterval:0.5];
data = [NSData dataWithContentsOfURL:[NSURL URLWithString:IMAGEURL]]; NSString *str = [NSString stringWithFormat:@"%d.线程%@完毕",count,[NSThread currentThread]];
//请求数据的任务由其他线程解决,所以LogTextView的内容由主线程更新,也只有主线程才能更新UI
[self performSelectorOnMainThread:@selector(updateTextViewWithString:) withObject:str waitUntilDone:YES];
return data;
}
4.上面的用到了主线程来调用updateTextViewWithString方法,因为只有主线程才能更新UI,updateTextViewWithString:这个方法负责把线程的执行信息显示在View上,代码如下:
//在ViewController上显示图片请求情况
-(void)updateTextViewWithString:(NSString *)str
{
NSString *old_str = [NSString stringWithFormat:@"%@\n%@",_logTextView.text, str]; _logTextView.text = old_str;
//改变Label的颜色,便于观察
[self tapTestButton:nil];
}
5.把请求完的图片加载到ImageView上
//更新图片
-(void) updateImageWithData:(NSData *)data
{
UIImage *image = [UIImage imageWithData:data];
[_testImage setImage:image];
}
6.加载图片的,也就是请求数据后在ImageView上显示
//由其他线程请求数据,由主线程来更新UI
-(void)loadImageWithThreadName:(NSString *)threadName
{
[[NSThread currentThread] setName:threadName]; NSData *data = [self getImageData];
[self performSelectorOnMainThread:@selector(updateImageWithData:) withObject:data waitUntilDone:YES];
}
二、通过各种方式来
1.同步请求图片测试,请求数据和更新UI都放在主线程中顺序执行,这样在请求数据的时候UI会卡死,代码如下;
//同步请求图片,视图阻塞的,因为主线程被占用,无法进行视图的更新
- (IBAction)tapButton:(id)sender {
NSData *data = [self getImageData];
[self updateImageWithData:data];
}
2.NSThread创建线程测试,用detachNewThreadSelector方法来创建新的线程会自动启动并执行,而不用调用start方法。代码如下:
//NSThread
- (IBAction)tapButton2:(id)sender {
//点击一次button就创建一个新的线程来请求图片数据
for (int i = ;i < ; i ++) {
[NSThread detachNewThreadSelector:@selector(loadImageWithThreadName:) toTarget:self withObject:@"NSThread"];
}
}
3.NSInvocationOperation的使用,新建一个调用操作,然后添加到队列中执行,代码如下:
//NSInvocationOperation
- (IBAction)tapInvocationOperation:(id)sender { //上面的调用操作需要放到调用队列里才执行的
//创建操作队列
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; for (int i = ;i < ; i ++) {
//实例化一个调用操作,来执行数据请求
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadImageWithThreadName:) object:@"Invocation"];
//把上面的调用操作放到操作队列里,队列会自动开启一个线程调用我们指定的方法
[operationQueue addOperation:invocationOperation];
}
}
4.block的操作,新建一个block操作,并添加到队列中执行,代码如下:
//BlockOperation
- (IBAction)tapBlockOperation:(id)sender {
__weak __block ViewController *copy_self = self; //创建BlockOperation
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
[copy_self loadImageWithThreadName:@"Block"];
}]; //添加到操作队列
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue addOperation:blockOperation]; for (int i = ;i < ; i ++) { //另一种方式
[operationQueue addOperationWithBlock:^{
[copy_self loadImageWithThreadName:@"Block"];
}];
}
}
5.GCD中的串行队列:
//串行队列
- (IBAction)tapGCDserialQueue:(id)sender {
//创建串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("mySerialQueue", DISPATCH_QUEUE_SERIAL); __weak __block ViewController *copy_self = self; for (int i = ;i < ; i ++) {
//异步执行队列
dispatch_async(serialQueue, ^{
[copy_self loadImageWithThreadName:@"Serial"];
});
} }
6.GCD中的并行队列:
//并行队列
- (IBAction)tapGCDConcurrentQueue:(id)sender {
//创建并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("myConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
__weak __block ViewController *copy_self = self; for (int i = ;i < ; i ++) {
//异步执行队列
dispatch_async(concurrentQueue, ^{
[copy_self loadImageWithThreadName:@"Concurrent"];
}); } }
以上是各个按钮对应的方法,下面的截图是执行结果:


三、线程间的同步问题(为我们的线程添加上同步锁)
在操作系统中讲多线程时有一个名词叫脏数据,就是多个线程操作同一块资源造成的,下面就修改一下代码,让数据出现问题,然后用同步锁来解决这个问题
1.在getImageData方法(标题一中的第3个方法)中有两条语句。这个用来显示线程的标号。上面的标号是没有重复的。
_count ++;
int count = _count;
在两条语句中间加一个延迟,如下:
_count ++;
[NSThread sleepForTimeInterval:];
int count = _count;
如果运行的话,会有好多标号是重复的,如图一,__count是成员变量,多个线程对此他进行操作,所以会出现标号不一致的情况,下面我们加上同步锁
(1)用NSLock加同步锁,代码如下:
//通过NSLock加锁
[_lock lock];
_count ++;
[NSThread sleepForTimeInterval:];
int count = _count;
[_lock unlock];
(2)通过@synchronized加同步锁,代码如下:
//通过synchronized加锁
int count;
@synchronized(self){
_count ++;
[NSThread sleepForTimeInterval:];
count = _count;
}
加锁前后的运行效果如下:

GCD的串行队列开始执行的顺序如下,下面是是在一个线程中按FIFO的顺序执行的:

GCD中的并行队列,是在不同的线程中同时执行的:

今天博客中的内容还是蛮多的,如果之前接触过Java的多线程的东西,或者其他语言中的多线程的话,理解起来应该问题不大。
iOS开发之多线程技术(NSThread、OperationQueue、GCD)的更多相关文章
- iOS开发之多线程(NSThread、NSOperation、GCD)
整理一些多线程相关的知识. 并行 & 并发 1.并行:并行是相对于多核而言的,几个任务同时执行.2.并发:并发是相对于单核而言的,几个任务之间快速切换运行,看起来像是"同时" ...
- iOS开发之多线程技术
本篇争取一篇讲清讲透,依然将通过四大方面清晰的对iOS开发中多线程的用法进行详尽的讲解: 一.什么是多线程 1)多线程执行原理 2)线程与进程 3)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...
- iOS的三种多线程技术NSThread/NSOperation/GCD
1.iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的"并发"技术,使得程序员可以不再去关心 ...
- iOS开发之多线程技术——GCD篇
本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...
- iOS开发之多线程技术—GCD篇
本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...
- 多线程技术 NSThread & NSOperation & GCD
多线程:在iOS开发中,用到多线程的处理问题的时候有很多,比如异步下载数据时刷新界面等等. 引入多线程来处理问题的关键就是,基于多线程可以使界面更加流畅,防止界面假死. 界面假死:比如你单击一个按钮来 ...
- iOS开发之多线程技术——NSOperation篇
本篇将从四个方面对iOS开发中使用到的NSOperation技术进行讲解: 一.什么是NSOperation 二.我们为什么使用NSOperation 三.在实际开发中如何使用NSOperation ...
- iOS开发:多线程技术概述
一.概述 线程(thread):用于指代独立执行的代码段. 进程(process):用于指代一个正在运行的可执行程序,它可以包含多个线程. 任务(task):用于指代抽象的概念,表示需要执行工作. 多 ...
- Ios开发之多线程编程——NSThread
IOS程序在运行的时候是通过主线程来进行UI视图的更新和响应屏幕触摸事件,但是,在视图更新的时候,会有一些非常耗时的工作,这样我们会出现系统出现卡顿的现象,这是因为主线程堵塞造成的,这样会使用户体验非 ...
随机推荐
- 简单谈谈如何利用h5实现音频的播放
作者:白狼 出处:http://www.manks.top/article/h5_audio本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律 ...
- UML类图关系--继承(泛化)、实现、关联、聚合、组合、依赖
在UML类图中,常见的有以下几种关系: 泛化(Generalization), 实现(Realization),关联(Association),聚合(Aggregation),组合(Composi ...
- C#窗体中读取修改xml文件
由于之前没有操作过xml文件,尤其是在窗体中操作xml,脑子一直转不动,而且很抵制去做这个功能,终于还是突破了自己通过查询资料完成了这个功能,在此记录一下自己的成果. 功能说明:程序中存在的xml文件 ...
- CF2.E
E. Comments time limit per test 2 seconds memory limit per test 256 megabytes input standard input o ...
- Mysql 学习笔记2
(1)MySQL查看表占用空间大小 //先进去MySQL自带管理库:information_schema //自己的数据库:dbwww58com_kuchecarlib //自己的表:t_carmod ...
- 一眼看懂深浅拷贝(clone)-C#
这是使用的是序列化的方式实现深拷贝 [Serializable] class Person:ICloneable { /// <summary> /// 字符串在clone 中类似于值类型 ...
- mysql 连接慢的问题(超过了1秒)
http://www.cnblogs.com/isenhome/p/5133547.html 症状描述 本机连接mysql速度很快 远程ping mysql主机速度正常 远程连接mysql速度需要等待 ...
- ormlite的使用方法
ormlite是什么? 简单来说,就是我们定义一个实体类,利用这个框架,它可以帮我们吧这个实体映射到我们的数据库中,在Android中是SQLite,数据中的字段就是我们定义实体的成员变量. 官网地址 ...
- asp.net中的<%%> <%#%> <%=%>形式的详细用法 (转载)
博客分类: ASP.NET 一. <%%>这种格式实际上就是和asp的用法一样的,只是asp中里面是vbscript或者javascript代码,而在asp.net中是.net平台下支 ...
- easyUI datagrid 根据查询条件 选中对应数据的行
开始 输入了 土豆,南瓜,再次是小青菜,每次输入点击搜索的时候(模糊查询),选中的当前数据对应的行 在做之前,在网上查询了许多资料,也在技术群里问过许多次,弄了好久终于好了. 第一次写博客真不知道写啥 ...