主线程:线程是进程的基本执行单元,一个iOS程序运行后,默认会开启1条线程,称为“主线程”又叫“UI线程”
主线程的主要作用
1.显示\刷新UI界面
2.处理UI事件(比如点击事件、滚动事件、拖拽事件等)
iOS有四个多线程解决方案
一. Pthreads
这是一套在很多操作系统上都通用的多线程API,所以移植性很强(然并卵),当然在 iOS 中也是可以的。不过这是基于 c语言
的框架,使用起来这酸爽!感受一下
1.包含头文件
#import <pthread.h>
2.创建线程,并执行任务
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
pthread_t thread;
//创建一个线程并自动执行
pthread_create(&thread, NULL, start, NULL);
}
void *start(void *data) {
NSLog(@"%@", [NSThread currentThread]);
return NULL;
}
到了这里也许你还会问 到底这个线程到底操作了什么 别急 跟着小龙哥看下一个
二.NSThread
经过苹果封装后的,并且完全面向对象的。所以你可以直接操控线程对象,非常直观和方便。但是,它的生命周期还是需要我们手动管理,所以这套方案也是偶尔用用,比如 [NSThread currentThread],它可以获取当前线程类,你就可以知道当前线程的各种属性,用于调试十分方便。下面来看看它的一些用法。
1.创建启动异步
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
2.创建启动同步完成
1.直接创建并自动启动
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
2.使用 NSObject 的方法创建并自动启动
[self performSelectorInBackground:@selector(run:) withObject:nil];
注意:
Note: The performSelector: method and related selector-invoking methods are not imported in Swift because they are inherently unsafe.
因为安全问题 苹果在swift中取消了performSelector这个方法
3.NSThread常用方法
除了创建启动外,NSThread 还以很多方法,下面我列举一些常见的方法,当然我列举的并不完整,更多方法大家可以去类的定义里去看。
//取消线程
- (void)cancel;
//启动线程
- (void)start;
//判断某个线程的状态的属性
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;
//设置和获取线程名字
-(void)setName:(NSString *)n;
-(NSString *)name;
//获取当前线程信息
+ (NSThread *)currentThread;
//获取主线程信息
+ (NSThread *)mainThread;
//使当前线程暂停一段时间,或者暂停到某个时刻
+ (void)sleepForTimeInterval:(NSTimeInterval)time;
+ (void)sleepUntilDate:(NSDate *)date;
三.GCD
Grand Central Dispatch 主要的线程优化技术
他最伟大的优点在于它会自动管理线程的生命周期(创建线程、调度任务、销毁线程)使用起来非常方便
1.如何使用GCD
首先我们要明白两个非常重要的概念
- 任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式: 同步执行 和 异步执行,他们之间的区别是 是否会创建新的线程。
同步(sync) 和 异步(async) 的主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕!
如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。
如果是 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。
- 队列:用于存放任务。一共有两种队列, 串行队列 和 并行队列
2.创建队列
- 1.主队列
dispatch_queue_t queue = ispatch_get_main_queue();
- 自己创建的队列:
自己可以创建 串行队列, 也可以创建 并行队列。第二个参数用来表示创建的队列是串行的还是并行的
- 2.1创建串行队列
DISPATCH_QUEUE_SERIAL 或 NULL 表示
- 2.2创建并行队列
-DISPATCH_QUEUE_CONCURRENT
//串行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
3.全局并行队列
只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3.创建任务
- 同步任务:会阻塞当前线程 (SYNC)
dispatch_sync(<#queue#>, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
});
- 异步任务:不会阻塞当前线程 (ASYNC)
dispatch_async(<#queue#>, ^{
//code here
NSLog(@"%@", [NSThread currentThread]);
});
4.队列组
队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。下面是使用方法,这是一个很实用的功能。
//1.创建队列组
dispatch_group_t group = dispatch_group_create();
//2.创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//3.多次使用队列组的方法执行任务, 只有异步方法
//3.1.执行3次循环
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 3; i++) {
NSLog(@"group-01 - %@", [NSThread currentThread]);
}
});
//3.2.主队列执行8次循环
dispatch_group_async(group, dispatch_get_main_queue(), ^{
for (NSInteger i = 0; i < 8; i++) {
NSLog(@"group-02 - %@", [NSThread currentThread]);
}
});
//3.3.执行5次循环
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"group-03 - %@", [NSThread currentThread]);
}
});
//4.都完成后会自动通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"完成 - %@", [NSThread currentThread]);
});
四 NSOperation & NSOperationQueue
NSOperation 是苹果公司对 GCD 的封装,完全面向对象,所以使用起来更好理解。 大家可以看到 NSOperation 和
NSOperationQueue 分别对应 GCD 的 任务 和 队列 。操作步骤也很好理解
五 NSOperation & NSOperationQueue
我们进行完多线程操作或 都需要回到主线程 接下来 就是讲到上面的四种方法是如何回到主线程(UI线程逻辑中的)
5.1 NSThread
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];
5.2 GCD
dispatch_async(dispatch_get_main_queue(), ^{
});
5.3 NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];