简单低调有效-iOS多线程

多线程在开发过程中的作用想必每个人都很清楚,极大程度上的利用cpu提高程序的运行效率和用户体验,今天就来理一下在iOS开发过程中常用到的几个关于多线程的类。

NSThread

NSThread的使用更加面向对象,简单易用,并且可以直接操作线程对象,但是在实际的运用中使用的并不是很多,是因为直接操作线程就以为着要自己管理线程,所以NSThread的使用并不是最多的。下面看一下NSThread的具体使用方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 创建1.
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];

thread.name = @"my-thread";

[thread start];

// 创建2.
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"rose"];

// 创建3.
[self performSelectorInBackground:@selector(run:) withObject:@"jack"];

// 耗时操作
- (void)run:(NSString *)param
{
}
// 其他
[NSThread sleepForTimeInterval:2]; // 让线程睡眠2秒(阻塞2秒)
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
[NSThread sleepUntilDate:[NSDate distantFuture]];// 睡到死。。
[NSThread exit]; // 直接退出线程
[NSThread currentThread]; // 当前线程
[NSThread mainThread]; // 主线程
// 加锁 ,互斥锁,缺点需要消耗大量的CPU资源
// 线程同步
@synchronized(self) {
// 需要锁定的代码
}
// 延迟执行
[self performSelector:<#(nonnull SEL)#> withObject:nil afterDelay:<#(NSTimeInterval)#>];

// 线程通讯

// 回到主线程,显示图片
[self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];

[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];// YES 是等完事,向下走 NO就是不等,直接走

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

GCD

方式 并发队列 手动创建串行队列 主队列
同步(sync) 没有开启新线程,行执行任务 没有开启新线程,行执行任务 没有开启新线程,行执行任务
异步(async) 开启新线程,并发行执行任务 开启新线程,行执行任务 没有开启新线程,行执行任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 创建并发队列
dispatch_queue_t queue = dispatch_queue_create("com.viverc.queue", DISPATCH_QUEUE_CONCURRENT);
// 创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.viverc.queue", DISPATCH_QUEUE_SERIAL);// 第二个参数为NULL也可
// 获得全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 获得主队列, 使用的时候注意点,别玩死就OK
dispatch_queue_t queue = dispatch_get_main_queue();

// 其他

// 不能是全局的,然后会分开(自己领会吧。。)
dispatch_barrier_async(<#dispatch_queue_t queue#>, <#^(void)block#>)

// 延迟
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

});

// 快速遍历
dispatch_apply 将外面的线程(main线程)阻塞了, 他会等待其他所有的循环运行完毕才会往下执行
dispatch_apply(3, queue, ^(size_t index) {
NSLog(@"apply loop: %zu, %@", index, [NSThread currentThread]);
});

// 队列组
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{
});
dispatch_group_async(group, queue, ^{
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
});

NSOperation

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 在主线程
NSLog(@"下载1------%@", [NSThread currentThread]);
}];
// 添加额外的任务(在子线程执行)
[op addExecutionBlock:^{
NSLog(@"下载2------%@", [NSThread currentThread]);
}];

[op addExecutionBlock:^{
NSLog(@"下载3------%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"下载4------%@", [NSThread currentThread]);
}];

[op start];



// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 创建操作(任务)
// 创建NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download2) object:nil];

// 创建NSBlockOperation
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3 --- %@", [NSThread currentThread]);
}];

[op3 addExecutionBlock:^{
NSLog(@"download4 --- %@", [NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"download5 --- %@", [NSThread currentThread]);
}];


NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download6 --- %@", [NSThread currentThread]);
}];

// 创建YZGOperation // 自定义Operation,重写main方法
// 在耗时操作的时候加判断 if(self.isCancelled) return;
YZGOperation *op5 = [[YZGOperation alloc] init];

// 添加任务到队列中
[queue addOperation:op1]; // [op1 start]
[queue addOperation:op2]; // [op2 start]
[queue addOperation:op3]; // [op3 start]
[queue addOperation:op4]; // [op4 start]
[queue addOperation:op5]; // [op5 start]


- (void)download1
{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}

- (void)download2
{
NSLog(@"download2 --- %@", [NSThread currentThread]);
}

简单方法

1
2
3
4
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}];

一些属性

1
2
3
4
5
6
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发操作数
queue.maxConcurrentOperationCount = 1; // 就变成了串行队列
queue.suspended = YES;// 暂停执行
[queue cancelAllOperations]; // 取消

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
类似于GCD 队列组
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download1----%@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download2----%@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3----%@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"download4----%@", [NSThread currentThread]);
}
}];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download5----%@", [NSThread currentThread]);
}];
op5.completionBlock = ^{
NSLog(@"op5执行完毕---%@", [NSThread currentThread]);
};

// 设置依赖
[op3 addDependency:op1];
[op3 addDependency:op2];
[op3 addDependency:op4];

[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
[queue addOperation:op4];
[queue addOperation:op5];

线程间通讯

[[[NSOperationQueue alloc] init] addOperationWithBlock:^{
    // 图片的网络路径
   NSURL *url = [NSURL URLWithString:@"http://i1.piimg.com/569091/4d218e7a3a6bd868s.jpg"];
    // 加载图片
    NSData *data = [NSData dataWithContentsOfURL:url];
    // 生成图片
    UIImage *image = [UIImage imageWithData:data];

    // 回到主线程
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        self.imageView.image = image;
    }];
}];