首页 > 代码库 > iOS 多线程

iOS 多线程

【理论】

进程:一个可执行的程序

任务:一块可执行的代码

线程:指的是一个独立的代码执行路径,线程是代码执行路径的最小单位

串行和并行:串行是一次只能执行一个任务,并行是一次能执行多个任务

并行:是CPU的多核芯同时执行多个任务  

并发:是单核CPU交替执行两个任务

 

【iOS 线程简述】

    iOS 线程有三种实现的方式:

  1.NSThread

  2.NSOperation

  3.GCD

  三者从上到下 越来越抽象,使用越来越简单。

 

一、NSThread

创建方式:

//方法一:直接创建线程并且开始运行线程,
  [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];

//方法二:先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
   NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
    [thread start];

//方法三:隐式创建一个线程
[NSObject performSelectorInBackground:@selector(downloadImage:) withObject:kURL];


线程之间的通讯
当下载完成以后 需要通知主线程去刷新UI
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
        
/** performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
    performSelector:onThread:withObject:waitUntilDone:
         **/

  

 

举个栗子: 

#pragma mark - NSThread的使用
- (void)createNewThread {
    /** 参数的意义:
     selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
     target  :selector消息发送的对象
     argument:传输给target的唯一参数,也可以是nil
     **/
    
    //方法一:直接创建线程并且开始运行线程,
    [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];
    
    
    //方法二:先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
    [thread start];

    
    //方法三:隐式创建一个线程
    [self performSelectorInBackground:@selector(downloadImage:) withObject:kURL];
}

- (void)downloadImage:(NSString *)url {
    
    NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
    UIImage *image = [[UIImage alloc]initWithData:data];
    if(image == nil){
        NSLog(@"image error");
    }else{
        [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
        
        /** performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
            performSelector:onThread:withObject:waitUntilDone:
         **/
    }
}

- (void)updateUI:(UIImage*)image {
    self.imageView.image = image;
}

 

二、NSOperation

  

三、GCD

<style>p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px "Microsoft YaHei"; color: #2e2e2e } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px "Microsoft YaHei"; color: #2e2e2e; background-color: #ffffff } span.s1 { background-color: #ffffff } span.s2 { }</style>

简述:

Grand Central Dispatch 简称(GCD),以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。

这建立在任务并行执行的线程池模式的基础上的。

 

<style>p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px "Microsoft YaHei"; color: #2e2e2e } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px "Microsoft YaHei"; color: #2e2e2e; background-color: #ffffff } span.s1 { background-color: #ffffff } span.s2 { }</style>

原理:

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

一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。

GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行。

 

dispatch queue 系统中包含了三种:

 

Serial :串行

又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。

 

Concurrent :并行

又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。

 

Main dispatch queue 全局串行队列

它是全局可用的serial queue,它是在应用程序主线程上执行任务的。

 

 

<style>p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px "Microsoft YaHei"; color: #2e2e2e } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px "Microsoft YaHei"; color: #2e2e2e; background-color: #ffffff } span.s1 { background-color: #ffffff } span.s2 { }</style>

1、常用的方法dispatch_async

为了避免界面在处理耗时的操作时卡死,例如:读取网络数据, 数据库读写等,我们会在非主线程线程中( Main dispatch queue 等串行队列)处理这些操作,然后通知主线程更新界面。

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

 

 实际应用

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;   
         });   
    }   
});

使用的话看起来,简单清晰的很多。

 

注:

<style>p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px "Microsoft YaHei"; color: #2e2e2e; background-color: #ffffff } span.s1 { }</style>

系统给每一个应用程序提供了三个concurrent dispatch queues。这三个并发调度队列是全局的,它们只有优先级的不同。不需要去创建。只需要通过使用函数dispath_get_global_queue 去get获得队列,如下:

#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

  

 

 

iOS 多线程