IOS面试专题

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

2017-01-15  本文已影响89人  张不二01
一,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],下面还是细看一下各种方法

    self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(selling) object:nil];
    [self.thread1 start];
    [NSThread detachNewThreadSelector:@selector(test2:) toTarget:self withObject:@"zhangdanfeng"];
    [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拓展:

    [NSThread sleepForTimeInterval: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](https://img.haomeiwen.com/i3930130/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,实现内部相应方法
上一篇下一篇

猜你喜欢

热点阅读