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的颜色的代码如下:

 1 //改变lable的颜色,在红绿颜色之间进行交换
 2 - (IBAction)tapTestButton:(id)sender {
 3     static int i = 1;
 4     if (i == 1) {
 5         _testLabel.backgroundColor = [UIColor redColor];
 6         i = 0;
 7     }
 8     else
 9     {
10         _testLabel.backgroundColor = [UIColor greenColor];
11         i = 1;
12     }
13
14 }

    3.从网络上获取图片,并使用主线程显示进程调用情况

 1 //从wang‘lu获取图片数据
 2 -(NSData *) getImageData
 3 {
 4
 5     _count ++;
 6     int count = _count;    //线程开始启动
 7   NSString *str = [NSString stringWithFormat:@"%d.线程%@",count,[NSThread currentThread]];    NSLog(@"%@",str);
 8     NSData *data;
 9     [NSThread sleepForTimeInterval:0.5];
10     data = [NSData dataWithContentsOfURL:[NSURL URLWithString:IMAGEURL]];
11
12     NSString *str = [NSString stringWithFormat:@"%d.线程%@完毕",count,[NSThread currentThread]];
13     //请求数据的任务由其他线程解决,所以LogTextView的内容由主线程更新,也只有主线程才能更新UI
14     [self performSelectorOnMainThread:@selector(updateTextViewWithString:) withObject:str waitUntilDone:YES];
15     return data;
16 }

    4.上面的用到了主线程来调用updateTextViewWithString方法,因为只有主线程才能更新UI,updateTextViewWithString:这个方法负责把线程的执行信息显示在View上,代码如下:

1 //在ViewController上显示图片请求情况
2 -(void)updateTextViewWithString:(NSString *)str
3 {
4     NSString *old_str = [NSString stringWithFormat:@"%@\n%@",_logTextView.text, str];
5
6     _logTextView.text = old_str;
7     //改变Label的颜色,便于观察
8     [self tapTestButton:nil];
9 }

    5.把请求完的图片加载到ImageView上

1 //更新图片
2 -(void) updateImageWithData:(NSData *)data
3 {
4     UIImage *image = [UIImage imageWithData:data];
5     [_testImage setImage:image];
6 }

    6.加载图片的,也就是请求数据后在ImageView上显示

1 //由其他线程请求数据,由主线程来更新UI
2 -(void)loadImageWithThreadName:(NSString *)threadName
3 {
4     [[NSThread currentThread] setName:threadName];
5
6     NSData *data = [self getImageData];
7     [self performSelectorOnMainThread:@selector(updateImageWithData:) withObject:data waitUntilDone:YES];
8 }

  二、通过各种方式来

    1.同步请求图片测试,请求数据和更新UI都放在主线程中顺序执行,这样在请求数据的时候UI会卡死,代码如下;

1 //同步请求图片,视图阻塞的,因为主线程被占用,无法进行视图的更新
2 - (IBAction)tapButton:(id)sender {
3     NSData *data = [self getImageData];
4     [self updateImageWithData:data];
5 }

    2.NSThread创建线程测试,用detachNewThreadSelector方法来创建新的线程会自动启动并执行,而不用调用start方法。代码如下:

1 //NSThread
2 - (IBAction)tapButton2:(id)sender {
3     //点击一次button就创建一个新的线程来请求图片数据
4     for (int i = 0;i < 10; i ++) {
5         [NSThread detachNewThreadSelector:@selector(loadImageWithThreadName:) toTarget:self withObject:@"NSThread"];
6     }
7  }

   

    3.NSInvocationOperation的使用,新建一个调用操作,然后添加到队列中执行,代码如下:

 1 //NSInvocationOperation
 2 - (IBAction)tapInvocationOperation:(id)sender {
 3
 4
 5     //上面的调用操作需要放到调用队列里才执行的
 6     //创建操作队列
 7     NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
 8
 9     for (int i = 0;i < 10; i ++) {
10         //实例化一个调用操作,来执行数据请求
11         NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadImageWithThreadName:) object:@"Invocation"];
12         //把上面的调用操作放到操作队列里,队列会自动开启一个线程调用我们指定的方法
13         [operationQueue addOperation:invocationOperation];
14     }
15 }

    4.block的操作,新建一个block操作,并添加到队列中执行,代码如下:

 1 //BlockOperation
 2 - (IBAction)tapBlockOperation:(id)sender {
 3     __weak __block ViewController *copy_self = self;
 4
 5     //创建BlockOperation
 6     NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
 7         [copy_self loadImageWithThreadName:@"Block"];
 8     }];
 9
10     //添加到操作队列
11     NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
12     [operationQueue addOperation:blockOperation];
13
14     for (int i = 0;i < 10; i ++) {
15
16         //另一种方式
17         [operationQueue addOperationWithBlock:^{
18             [copy_self loadImageWithThreadName:@"Block"];
19         }];
20     }
21 }

    5.GCD中的串行队列:

 1 //串行队列
 2 - (IBAction)tapGCDserialQueue:(id)sender {
 3     //创建串行队列
 4     dispatch_queue_t serialQueue = dispatch_queue_create("mySerialQueue", DISPATCH_QUEUE_SERIAL);
 5
 6
 7     __weak __block ViewController *copy_self = self;
 8
 9
10     for (int i = 0;i < 10; i ++) {
11         //异步执行队列
12         dispatch_async(serialQueue, ^{
13             [copy_self loadImageWithThreadName:@"Serial"];
14         });
15     }
16
17
18 }

    6.GCD中的并行队列:

 1 //并行队列
 2 - (IBAction)tapGCDConcurrentQueue:(id)sender {
 3     //创建并行队列
 4     dispatch_queue_t concurrentQueue = dispatch_queue_create("myConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
 5     __weak __block ViewController *copy_self = self;
 6
 7     for (int i = 0;i < 10; i ++) {
 8         //异步执行队列
 9         dispatch_async(concurrentQueue, ^{
10             [copy_self loadImageWithThreadName:@"Concurrent"];
11         });
12
13     }
14
15 }

    以上是各个按钮对应的方法,下面的截图是执行结果:

  三、线程间的同步问题(为我们的线程添加上同步锁)

    在操作系统中讲多线程时有一个名词叫脏数据,就是多个线程操作同一块资源造成的,下面就修改一下代码,让数据出现问题,然后用同步锁来解决这个问题

    1.在getImageData方法(标题一中的第3个方法)中有两条语句。这个用来显示线程的标号。上面的标号是没有重复的。

1     _count ++;
2     int count = _count;

    在两条语句中间加一个延迟,如下:

    _count ++;
    [NSThread sleepForTimeInterval:1];
    int count = _count;

    如果运行的话,会有好多标号是重复的,如图一,__count是成员变量,多个线程对此他进行操作,所以会出现标号不一致的情况,下面我们加上同步锁

     (1)用NSLock加同步锁,代码如下:

1     //通过NSLock加锁
2     [_lock lock];
3     _count ++;
4     [NSThread sleepForTimeInterval:1];
5     int count = _count;
6     [_lock unlock];

    (2)通过@synchronized加同步锁,代码如下:

1     //通过synchronized加锁
2     int count;
3     @synchronized(self){
4         _count ++;
5         [NSThread sleepForTimeInterval:1];
6          count = _count;
7     }

      加锁前后的运行效果如下:

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

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

  今天博客中的内容还是蛮多的,如果之前接触过Java的多线程的东西,或者其他语言中的多线程的话,理解起来应该问题不大。

时间: 2024-10-14 04:40:05

iOS开发之多线程技术(NSThread、OperationQueue、GCD)的相关文章

学习IOS开发网络多线程篇--NSThread/GCD/

NSThread:利用NSThread创建和启用一个线程 1. NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];,调用后调用[thread start]; 2. 创建线程后自动启动线程 ,[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil]; 3. 隐式创建

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

1.iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的"并发"技术,使得程序员可以不再去关心线程的具体使用问题 NSOperation/NSOperationQueue 面向对象的线程技术 GCD -- Grand Central Dispatch(派发) 是基于C语言的框架,可以充分利用多核,是苹果推荐使用的多线程技术. 以上这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,

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

本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & Asynchronous 同步 & 异步 二.Serial Queues & Concurrent Queues 串行 & 并发 三.Global Queues全局队列 四.Main Queue主队列 五.同步的作用 六.dispatch_time延迟操作 七.线程安全(单例dispa

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

本篇将从四个方面对iOS开发中使用到的NSOperation技术进行讲解: 一.什么是NSOperation 二.我们为什么使用NSOperation 三.在实际开发中如何使用NSOperation 1.自定义NSOperation 2.NSOperation的基本使用 3.NSOperation实现线程间通信 1)利用代理进行消息传递 2)利用通知实现消息传递 3)利用block进行消息传递 四.与GCD比较 一.什么是NSOperation NSOperation是一个抽象的基类,表示一个独

iOS开发:多线程技术概述

一.概述 线程(thread):用于指代独立执行的代码段. 进程(process):用于指代一个正在运行的可执行程序,它可以包含多个线程. 任务(task):用于指代抽象的概念,表示需要执行工作. 多线程的替代方法: Operation objects(操作对象):操作对象可能创建线程更快,因为它们使用内核里面常驻线程池里面的线程来节省创建的时间,而不是每次都创建新的线程. Grand Central Dispatch(GCD):如果你更关注你任务的完成而不是线程的管理,那么GCD是很好的选择,

IOS开发-多线程编程技术(Thread、Cocoa operations、GCD)

前言:在软件开发中,多线程编程技术被广泛应用,相信多线程任务对我们来说已经不再陌生了.有了多线程技术,我们可以同做多个事情,而不是一个一个任务地进行.比如:前端和后台作交互.大任务(需要耗费一定的时间和资源)等等.也就是说,我们可以使用线程把占据时间长的任务放到后台中处理,而不影响到用户的使用. 线程的定义: 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行.也可以把它理

iOS开发之多线程——GCD介绍

iOS开发之多线程——GCD的介绍 一.简单介绍 1.GCD ( Grand Central Dispatch) 可以翻译为“中枢调度器”.纯C语言,并且提供了非常强大的函数. 2.GCD 有什么优势: GCD是苹果公司为多核的并行运算提出的解决方案 GCD会自动利用更多地CPU 内核 (比如双核.四核) GCD会自动管理线程的生命周期 (创建线程.调度任务.销毁线程) 程序猿只需要告诉GCD想要执行设呢任务,不需要编写任何线程管理代码. 二.任务和队列 GCD中有两个核心概念 (1)任务: 执

ios多线程(NSThread、GCD、NSOperation)

ios中得多线程技术主要使用3种:NSThread.NSOperation和GCD 一.NSThread: 最轻量级方法,但是不安全需要手动加锁,需要自己管理生命周期 NSThread的使用方法有2种: // 第一种,需要start 1 NSThread *th1 = [[NSThread alloc] initWithTarget:self selector:@selector(btnClick) object:nil]; 2     [th1 setName:@"线程1"]; 3 

OS X 和iOS 中的多线程技术(上)

OS X 和iOS 中的多线程技术(上) 本文梳理了OS X 和iOS 系统中提供的多线程技术.并且对这些技术的使用给出了一些实用的建议. 多线程的目的:通过并发执行提高 CPU 的使用效率,进而提供程序运行效率. 1.线程和进程 进程 什么是进程 进程是指在计算机系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行中其专用且受保护的内存空间内 比如同时打开 Xcode .Safari ,系统就会分别启动两个进程 通过活动监视器可以查看Mac系统中所开启的进程 线程 什么是线程 一