在前面的博客中如果用到了异步请求的话,也是用到的第三方的东西,没有正儿八经的用过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)的更多相关文章

  1. iOS开发之多线程(NSThread、NSOperation、GCD)

    整理一些多线程相关的知识. 并行 & 并发 1.并行:并行是相对于多核而言的,几个任务同时执行.2.并发:并发是相对于单核而言的,几个任务之间快速切换运行,看起来像是"同时" ...

  2. iOS开发之多线程技术

    本篇争取一篇讲清讲透,依然将通过四大方面清晰的对iOS开发中多线程的用法进行详尽的讲解: 一.什么是多线程 1)多线程执行原理 2)线程与进程 3)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...

  3. iOS的三种多线程技术NSThread/NSOperation/GCD

    1.iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的"并发"技术,使得程序员可以不再去关心 ...

  4. iOS开发之多线程技术——GCD篇

    本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...

  5. iOS开发之多线程技术—GCD篇

    本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...

  6. 多线程技术 NSThread & NSOperation & GCD

    多线程:在iOS开发中,用到多线程的处理问题的时候有很多,比如异步下载数据时刷新界面等等. 引入多线程来处理问题的关键就是,基于多线程可以使界面更加流畅,防止界面假死. 界面假死:比如你单击一个按钮来 ...

  7. iOS开发之多线程技术——NSOperation篇

    本篇将从四个方面对iOS开发中使用到的NSOperation技术进行讲解: 一.什么是NSOperation 二.我们为什么使用NSOperation 三.在实际开发中如何使用NSOperation ...

  8. iOS开发:多线程技术概述

    一.概述 线程(thread):用于指代独立执行的代码段. 进程(process):用于指代一个正在运行的可执行程序,它可以包含多个线程. 任务(task):用于指代抽象的概念,表示需要执行工作. 多 ...

  9. Ios开发之多线程编程——NSThread

    IOS程序在运行的时候是通过主线程来进行UI视图的更新和响应屏幕触摸事件,但是,在视图更新的时候,会有一些非常耗时的工作,这样我们会出现系统出现卡顿的现象,这是因为主线程堵塞造成的,这样会使用户体验非 ...

随机推荐

  1. 20155315庄艺霖--对做中学的理解及对c语言和Java的看法

    关于做中学的理解及技能训练的思考 在写这篇博客之前,我首先阅读了娄老师的博客,对做中学的概念很感兴趣.我们常说知识要学以致用,做中学强调的是在用的过程中有新的收获和体会来进一步巩固学习.细数我学过的课 ...

  2. ExecutorService与ThreadPoolTaskExecutor

    1.ExecutorService private static ExecutorService exec = null; public static ExecutorService getExecu ...

  3. sass和compass的配置

    http://note.youdao.com/share/?id=4f57187f9695bcaadf80516187d2de0e&type=note 当执行安装sass出错时,可以试试这个命 ...

  4. css中单位px、pt、em和rem的区别

    国内的设计师大都喜欢用px,而国外的网站大都喜欢用em和rem,那么三者有什么区别,又各自有什么优劣呢? px :像素(Pixel).相对长度单位.像素px是相对于显示器屏幕分辨率而言的.(引自CSS ...

  5. Web开发者需养成的好习惯

    Web开发者需养成的8个好习惯 每个行业有着每个行业的标准和一些要求,自己只是一个进入前端领域的小白,但是深刻的知道,习惯很重要,就Web开发分享一下,要养成的一些好的习惯. 优秀的Web开发人员工作 ...

  6. MySQL选择合适的数据类型

    一.char和varchar char是固定长度的,查询速度比varchar速度快的多.char的缺点是浪费存储空间. 检索char列时,返回的结果会删除尾部空格,所以程序需要对为空格进行处理. 对于 ...

  7. oracle--导出、导入blob类型的字段

    blob是oracle中的一个数据类型,保存的是压缩后的二进制形式的大数据. 数据迁移如果涉及到blob字段,都不好处理,因为无法用常规方法进行操作,如:使用select查看该字段,也无法用inser ...

  8. International Conference for Smart Health 2015 Call for Papers

    Advancing Informatics for healthcare and healthcare applications has become an international researc ...

  9. .NET 4.0 版本号

    .NET 4.5.1, .NET 4.5 和 .NET 4.0 均基于 .NET 4.0 CLR,而 .NET 4.5 对 CLR进行了升级和Bug修复. .NET 4.0 - 4.0.30319.1 ...

  10. 前端神器avalonJS入门(三)

    本章将介绍如何使用avalon来实现前端路由功能. 我们需要用到两个avalon路由配套模块—— mmHistory.js 和 mmRouter.js .其中mmHistory是用于历史管理,它会劫持 ...