iOS多线程入门之NSThread,NSOperation,GCD

一 线程的概念


一个运行着的程序就是一个进程或者叫做一个任务,一个进程至少包含一个线程,线程就是程序的执行流。Mac和iOS中的程序启动,创建好一个进程的同时, 一个线程便开始运行,这个线程叫主线程。主线程在程序中的地位和其他线程不同,它是其他线程最终的父线程,且所有界面的显示操作即AppKit或 UIKit的操作必须在主线程进行。 

系统中的每一个进程都有自己独立的虚拟内存空间,而同一个进程中的多个线程则共用进程的内存空间。每创建一个新的线程,都需要一些内存(如每个线程有自己的Stack空间)和消耗一定的CPU时间。另外当多个线程对同一个资源出现争夺的时候需要注意线程安全问题。

二 iOS的三种多线程技术特点:

1.NSThread:

    1> 优点:NSThread对象建立一个线程非常方便;

    2> 缺点:要使用NSThread管理多个线程非常困难,不推荐使用;

    3> 技巧:使用[NSThread currentThread]跟踪任务所在线程,适用于这三种技术.

2.NSOperation/NSOperationQueue:

    1> 概念1:是使用GCD实现的一套Objective-C的API;

    2> 概念2是面向对象的多线程技术;

    3> 优点:提供了一些在GCD中不容易实现的特性,如:限制最大并发数量,操作之间的依赖关系.

3.GCD---Grand Central Dispatch:

    1> 概念:是基于C语言的底层API;

    2> 优点1:用Block定义任务,使用起来非常灵活便捷;

    3> 优点2:提供了更多的控制能力以及操作队列中所不能使用的底层函数.



三  NSThread

1、线程创建与启动

线程创建主要有二种方式:

  1. - (id)init; // designated initializer  
  2. - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument; 

当然,还有一种比较特殊,就是使用所谓的convenient method,这个方法可以直接生成一个线程并启动它,而且无需为线程的清理负责。这个方法的接口是:

  1. + (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument 

前两种方法创建后,需要手机启动,启动的方法是:

  1. - (void)start; 

eg: 

1.1:[NSThread detachNewThreadSelector:@selector(threadInMainMethod:) toTarget:self withObject:nil];
 
1.2:NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadInMainMethod:) object:nil];
 [myThread start]; 
1.3:  [obj performSelectorInBackground:@selector(threadMe) withObject:nil];


四 NSOperation/NSOperationQueue

使用 NSOperation的方式有两种,

一种是用定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。

另一种是继承NSOperation


创建方法

  1. NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self  
  2.                                                                            selector:@selector(downloadImage:)  
  3.                                                                              object:kURL];  
  4.       
  5.     NSOperationQueue *queue = [[NSOperationQueue alloc]init];  
  6.     [queue addOperation:operation];  

一个NSOperationQueue 操作队列,就相当于一个线程管理器,而非一个线程。因为你可以设置这个线程管理器内可以并行运行的的线程数量等等。

[queue setMaxConcurrentOperationCount:1]; 

添加和删除NSOperation的依赖对象 addDependency与removeDependency方法

设置优先级:setQueuePriority:

设置队列的最大并发数:maxConcurrentOperationCount

取消单个线程: 通过NSOperation的cancel方法

取消全部线程:通过NSOperationQueue的cancelAllOperations

暂停和继续:通过修改NSOperationQueue的suspended属性

五 GCD

GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。

1、dispatch_async

子线程处理耗时操作(读取网络数据,数据库操作等),主线程用于更新UI。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
    // 耗时的操作  
    dispatch_async(dispatch_get_main_queue(), ^{  
        // 更新界面  
    });  
});  


eg:图片下载,子线程用于网络请求,主线程更新imageview
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
    NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];  
    NSData * data = [[NSData alloc]initWithContentsOfURL:url];  
    UIImage *image = [[UIImage alloc]initWithData:data];  
    if (data != nil) {  
        dispatch_async(dispatch_get_main_queue(), ^{  
            self.imageView.image = image;  
         });  
    }  
});  


2、dispatch_group_async

dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。
eg:执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
dispatch_group_t group = dispatch_group_create();  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:1];  
    NSLog(@"group1");  
});  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:2];  
    NSLog(@"group2");  
});  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:3];  
    NSLog(@"group3");  
});  
dispatch_group_notify(group, dispatch_get_main_queue(), ^{  
    NSLog(@"updateUi");  
});  
dispatch_release(group);  
dispatch_group_async是异步的方法,运行后可以看到打印结果:

2012-09-25 16:04:16.737 gcdTest[43328:11303] group1
2012-09-25 16:04:17.738 gcdTest[43328:12a1b] group2
2012-09-25 16:04:18.738 gcdTest[43328:13003] group3
2012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi

每个一秒打印一个,当第三个任务执行后,upadteUi被打印。



3、dispatch_barrier_async的使用

dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

例子代码如下:

[cpp]  view plain copy
  1. dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);  
  2. dispatch_async(queue, ^{  
  3.     [NSThread sleepForTimeInterval:2];  
  4.     NSLog(@"dispatch_async1");  
  5. });  
  6. dispatch_async(queue, ^{  
  7.     [NSThread sleepForTimeInterval:4];  
  8.     NSLog(@"dispatch_async2");  
  9. });  
  10. dispatch_barrier_async(queue, ^{  
  11.     NSLog(@"dispatch_barrier_async");  
  12.     [NSThread sleepForTimeInterval:4];  
  13.   
  14. });  
  15. dispatch_async(queue, ^{  
  16.     [NSThread sleepForTimeInterval:1];  
  17.     NSLog(@"dispatch_async3");  
  18. });  

打印结果:

2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async

2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3

请注意执行的时间,可以看到执行的顺序如上所述。


  

其他用法请参照官方文档GCD



部分内容参照博客,感谢原作者容芳志 http://blog.csdn.net/totogo2010/article/details/8016129





你可能感兴趣的:(iOS开发)