iOS多线程之01四种实现方式

  • 一,pthread (几乎不用)
  • 二,NSThread (偶尔用,掌握最基本的几个常用方法)
  • 三,GCD (常用,C语言技术)
  • 四,NSOperation(常用,OC基于GCD的封装)
一,pthread (简单了解)

纯c代码,简单了解即可

#import <pthread.h>
@implementation ViewController
void *task(void *data){
    NSLog(@"zhangdanfeng---该函数执行的线程是---%@",[NSThread currentThread]);
    return NULL;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"当前线程是---%@", [NSThread currentThread]);
    
    //创建pthread,传入第一个pthread_t参数,第三个调用的函数
    pthread_t pthread;
    pthread_create(&pthread, NULL, task, NULL);
}
@end
二,NSThread (偶尔用,掌握最基本的几个常用方法)

有几个方法经常调用,比如取得当前线程等 [NSThread currentThread],下面还是细看一下各种方法

  • 1,创建线程方法一:(手动开启)
    self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(selling) object:nil];
    [self.thread1 start];
  • 2,创建线程方法二:(自动开启线程)
    [NSThread detachNewThreadSelector:@selector(test2:) toTarget:self withObject:@"zhangdanfeng"];
  • 3,隐式创建线程:
    [self performSelectorInBackground:@selector(test2:) withObject:@"ddddddd"];
    [self performSelector:@selector(test3:) onThread:[NSThread mainThread] withObject: @"zhang" waitUntilDone:NO];

    //注意和这个方法类似的但是不创建线程的方法:
    [self performSelector:@selector(test3:) withObject:@"lililiiili"];
    [self performSelector:@selector(test3:) withObject:@"zhangzhangzhang" afterDelay:1];

NSThread拓展:

  • 4,睡眠,阻塞线程:
    [NSThread sleepForTimeInterval:5];
  • 5,跳出线程:
    [NSThread exit];
```

 * 6,线程同步:加锁(多条线程抢夺同一资源才需要加锁,又叫互斥锁)
线程同步其实就是加锁,使得多条线程在同一条线程上同步执行。

```
while(1){
    @synthesize(self){
        <#code#>
    }
}
```

*NSThread线程通讯:*
* 7,默认在主线程方法中调用:

```
[self performSelectorOnMainThread:@selector(downloadFinished:) withObject:image waitUntilDone:YES;]
```
如果仅仅是想要设置图片,可以直接调用图片方法而不用重新写一个方法:

```
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES;]
```
* 8, 实例SDWebImage的简单实现:图片在子线程下载,主线程显示

```
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1,首先创建一个子线程,执行下载操作
    [self performSelectorInBackground:@selector(downloadImage:) withObject:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1484467449439&di=464f3f6b90d11305721f3cc4e720bc65&imgtype=0&src=http%3A%2F%2Fp2.gexing.com%2FG1%2FM00%2FBE%2FE3%2FrBACE1KMVZSQxt3FAACu1FpgT7M205.jpg"];
}

- (void)downloadImage: (NSString *)imageUrlStr{
    //2,这里是在子线程的方法中下载图片
    NSURL *url =[NSURL URLWithString:imageUrlStr];
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:data];
    
    //3,当我图片准备好了之后,就可以回到主线陈调用设置图片的方法
    //waitUntilDone:因为是回到主线程,所以这里是指是否能这个回到主线程的操作完成之后再继续往下运行我这个子线程的下面的操作
    [self performSelectorOnMainThread:@selector(setImageViewWithImage:) withObject:image waitUntilDone:nil];
}

- (void)setImageViewWithImage:(UIImage *)image{
    //4,回到主线程之后进行设置图片更新UI
    self.imageView.image = image;
}

@end
```


#####三,GCD(可以利用多核):常用,苹果公司C语言技术,Grand Central Dispatch
*注意NSThread是不能利用多核进行优化的*



*GCD        (常用,苹果公司C语言技术,Grand Central Dispatch)*

* 1,创建线程和队列:
 * 1.1,同步任务://不具备开启线程的能力
```
dispatch_sync();
```
 * 1.2,异步任务://具备开启线程的能力,但是只有在并发队列里才会开线程
```
dispatch_async();
```
 * 1.3,串行队列:任务一个接一个别调度
*主队列是一个特殊的串行队列*
```
dispatch_queue_create("zhang", NULL);//c语言字符串
```
 * 1.4,并发队列:可以同时调度多个任务执行,在异步下发挥作用。
```
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
```

* 2,,队列和同步异步混合使用:

 * ![Snip20170115_1.png](http://upload-images.jianshu.io/upload_images/3930130-56b96d166ce9f676.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

  *  2.1,同步和串行队列混合使用:也就是在当前队列执行任务,相当于默认设置,所以一般没必要用这个(主队列执行任务)
  * 2.2,同步和并行队列混合使用:在当前也就是主队列中行任务,只有一个线程,也就没有并发之说,和1是一样的,很少会用。(主队列执行任务)
  * 2.3,async和串行队列混合使用:常用,会开启一条子线程,串行一个一个任务执行
  * 2.4,async和并行队列混合使用:最常用,会开启多条线程同时执行多项任务

* 3,有两种特殊情况:
 * 3.1, async和主队列混合使用,这个时候能开启线程但是不会开启线程,一般这个情况只用在线程之间的通讯。
 * 3.1, sync和主队列混合使用,这个时候会被卡死,因为是一种循环等待机制。

* 4,GCD线程通讯:
```
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{//在全局并发队列中异步执行
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:data];
    //这里是不能用syn的,会卡住任务
    dispatch_async(dispatch_get_main_queue(), ^{//在异步执行完成之后返回到主队列执行(这里用sync和async是一样的)
        self.imaView.image = image;
    });
});
```
注意:
 * 4.1,如果一个button设置图片出现不明问题,试着更改button的方式为自定义custom
 * 4.2,属性名不能以new开头,new是一个特殊字符,如果使用可能无法启动程序
 * 4.3,GCD的所有API都在libdispatch.dylib框架中


* 5,GCD延迟执行操作:
```
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"-------aaa--------");
    NSLog(@"-------%@----------",[NSThread currentThread]);//在哪个线程里执行跟所添加的队列参数有关
});
```
* 其它延迟执行的操作:

* [NSThread sleepForTimeInterval:2];//(会卡住进程,所以一般不用)
* [self performSelector:@selector(download:) withObject:@"http://zhang.jpg" afterDelay:10];//(在当前线程调用)




* 6,GCD队列组的使用:

```
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    __block UIImage *image01 = nil;
    dispatch_group_async(group, queue, ^{
        NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/upload/upc/tx/photoblog/1503/17/c2/3974346_1426551981202_mthumb.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        image01 = [UIImage imageWithData:data];
    });

    __block UIImage *image02 = nil;
    dispatch_group_async(group, queue, ^{
        NSURL *url1 = [NSURL URLWithString:@"https://www.baidu.com/img/bd_logo1.png"];
        NSData *data1 = [NSData dataWithContentsOfURL:url1];
        image02 = [UIImage imageWithData:data1];
    });

    dispatch_group_notify(group, queue, ^{
        UIGraphicsBeginImageContextWithOptions(image01.size, NO, 0.0);
        [image01 drawInRect:CGRectMake(0, 0, image01.size.width, image01.size.height)];
        [image02 drawInRect:CGRectMake(image01.size.width- image02.size.width*.4, image01.size.height-image02.size.height*.4, image02.size.width*.4, image02.size.height*.4)];

        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imaView1.image = image;
        });
    });

```

#####四,NSOperation(常用,OC基于GCD的封装)

* 1,NSOPeration的基本使用:
  *NSOperation有三个子类:*
 * NSInvocationOperation
 * NSBlockOperation
 * 自定义子类继承Operation,实现内部相应方法
* 1.1,NSInvocationOperation(很少用,简单了解即可)

```
    //创建任务:
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(down) object:nil];
        
    //有两种执行任务的方式:
    //第一,直接调用operation的start方法:同步执行
    [operation start];
    //第二,创建线程对象,并添加到线程中:自动异步执行
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
```
* 1.2,NSBlockOperation:

```
    //创建任务:
    //有二种创建任务的方式:
    //第一,如下
    NSBlockOperation *operation = [[NSBlockOperation alloc] init];
    [operation addExecutionBlock:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];
    //第二,如下
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];
    //仅仅创建任务并不会自动执行
    //执行方式有两种:
    //第一,直接调用operation的start方法:同步执行
    [operation start];

    //第二创建线程对象,并添加到线程中:自动异步执行
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];

//blockOperation的简化写法:
    注意一般情况下为了方便,会简化创建和执行操作,把queue创建和任务创建合并:自动异步执行,如下:
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addExecutionBlock:^{
        NSLog(@"%@-----",[NSThread currentThread]);
    }];
```
```    
    最大并发数:
        queue.maxConcurrentOperationCount = 5;
    依赖,也就是前者需要在后者完成的基础上才能操作:
        [operation addDependency:operation01];(operation需要独立创建而不能用queue直接添加的快捷创建方式)
    设置完成后block:(和依赖类似,不过block需要在operation完成后才回开始)
        [operation setCompletionBlock:^{
            NSLog(@"zzzz");
        }];
    取消所有操
        [queue cancekAllOperations];
    暂停所有操作
        [queue setSuspended:YES];
    恢复所有操作
        [queue setSuspended:NO];
``` 
 * NSBlockOperation线程之间的通讯:

```
//方式一
[[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        //其它线程执行耗时操作
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        //主线程操作
    }
}]; 
//方式二
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES;]
//方式三
dispatch_async(dispatch_get_main_queue(), ^{
    //在异步执行完成之后返回到主队列执行
    self.imaView.image = image;
 })
```

* NSBlockOperation线程之间的依赖

```
    NSBlockOperation *operation01 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"operation01");
    }];
    NSBlockOperation *operation02 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"operation02");
    }];
    NSBlockOperation *operation03 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"operation03");
    }];
    NSBlockOperation *operation04 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"operation04");
    }];
    NSBlockOperation *operation05 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务完成");
    }];
    
//依赖必须先于队列之前添加
    [operation05 addDependency:operation04];
    [operation04 addDependency:operation03];
    [operation03 addDependency:operation02];
    [operation02 addDependency:operation01];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperations:@[operation01,operation02,operation03,operation04,operation05] waitUntilFinished:YES];
```
        
3,自定义子类继承Operation,实现内部相应方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容

  • NSThread 第一种:通过NSThread的对象方法 NSThread *thread = [[NSThrea...
    攻城狮GG阅读 784评论 0 3
  • 1. GCD简介 什么是GCD呢?我们先来看看百度百科的解释简单了解下概念 引自百度百科:Grand Centra...
    千寻_544f阅读 359评论 0 0
  • 一、前言 上一篇文章iOS多线程浅汇-原理篇中整理了一些有关多线程的基本概念。本篇博文介绍的是iOS中常用的几个多...
    nuclear阅读 2,043评论 6 18
  • 1. GCD简介 iOS开发中多线程的API主要有pthread,NSThread,NSOperation和GCD...
    安东_Ace阅读 1,246评论 0 6
  • 长的还可以,为什么总是爱的不容最后来一句,别总感冒了。总感冒对身体抵抗力有影响。也少熬夜了,多多运动,多出去走走,...
    大叔老了阅读 195评论 0 0