线程的注意点
1.不要同时开太多的线程(1~3条线程即可,不要超过5条)
2.线程概念
- 1)主线程 : UI线程,显示、刷新UI界面,处理UI控件的事件
- 2)子线程 : 后台线程,异步线程
3.不要把耗时的操作放在主线程,要放在子线程中执行
iOS的三种多线程技术
NSThread
- 使用NSThread对象建立一个线程非常方便
- 但是!要使用NSThread管理多个线程非常困难,不推荐使用
- 技巧!使用[NSThread currentThread]跟踪任务所在线程,适用于这三种技术
NSOperation/NSOperationQueue
- 是使用GCD实现的一套Objective-C的API
- 是面向对象的线程技术
- 提供了一些在GCD中不容易实现的特性,如:限制最大并发数量、操作之间的依赖关系
GCD —— Grand Central Dispatch
- 是基于C语言的底层API
- 用Block定义任务,使用起来非常灵活便捷
- 提供了更多的控制能力以及操作队列中所不能使用的底层函数
NSThread
1.创建和启动线程的3种方式
1)先创建,后启动
1234 // 创建NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:nil];// 启动[thread start];2)创建完自动启动
1 [NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:nil];3)隐式创建(自动启动)
1 [self performSelectorInBackground:@selector(download:) withObject:nil];2.常见方法
1)获得当前线程
1 + (NSThread *)currentThread;2)获得主线程
1 + (NSThread *)mainThread;3)睡眠(暂停)线程
12 + (void)sleepUntilDate:(NSDate *)date;+ (void)sleepForTimeInterval:(NSTimeInterval)ti;4)设置线程的名字
12 - (void)setName:(NSString *)n;- (NSString *)name;
线程同步
1.实质:为了防止多个线程抢夺同一个资源造成的数据安全问题
2.实现:给代码加一个互斥锁(同步锁)
123 @synchronized(self) {// 被锁住的代码}
GCD(Grand Central Dispatch)
1.队列和任务
1)任务 :需要执行什么操作
用block来封装任务
2)队列 :存放任务
全局的并发队列 : 可以让任务并发执行
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);自己创建的串行队列 : 让任务一个接着一个执行
1 dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue", NULL);主队列 : 让任务在主线程执行
1 dispatch_queue_t queue = dispatch_get_main_queue();2.执行任务的函数
1)同步执行 : 不具备开启新线程的能力
dispatch_sync...
2)异步执行 : 具备开启新线程的能力dispatch_async...
3.常见的组合
1)
dispatch_async
+ 全局并发队列
2)dispatch_async
+ 自己创建的串行队列4.线程间的通信
123456 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 执行耗时的异步操作...dispatch_async(dispatch_get_main_queue(), ^{// 回到主线程,执行UI刷新操作});});5.GCD的所有API都在libdispatch.dylib,Xcode会自动导入这个库
主头文件 :
#import <dispatch/dispatch.h>
6.延迟执行
1)
perform....
12 // 3秒后自动回到当前线程调用self的download:方法,并且传递参数:@"http://555.jpg"[self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];2)
dispatch_after...
123456 // 任务放到哪个队列中执行dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);double delay = 3; // 延迟多少秒dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{// 3秒后需要执行的任务});7.一次性代码
1234 static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{// 这里面的代码,在程序运行过程中,永远只会执行1次});
单例模式(懒汉式)
1.ARC
|
|
2.MRC
|
|
NSOperation和NSOperationQueue
1.队列的类型
1) 主队列
[NSOperationQueue mainQueue]
添加到”主队列”中的操作,都会放到主线程中执行2) 非主队列
[[NSOperationQueue alloc] init]
添加到”非主队列”中的操作,都会放到子线程中执行2.队列添加任务
12 - (void)addOperation:(NSOperation *)op;- (void)addOperationWithBlock:(void (^)(void))block;3.常见用法
1) 设置最大并发数
12 - (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;2) 队列的其他操作
取消所有的操作
- (void)cancelAllOperations;
暂停所有的操作
[queue setSuspended:YES];
恢复所有的操作
[queue setSuspended:NO];
4.操作之间的依赖
NSOperation之间可以设置依赖来保证执行顺序
[operationB addDependency:operationA];操作B依赖于操作A,等操作A执行完毕后,才会执行操作B。
注意:不能相互依赖,比如A依赖B,B依赖A;可以在不同queue的NSOperation之间创建依赖关系5.线程之间的通信
12345678 NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperationWithBlock:^{// 1.执行一些比较耗时的操作// 2.回到主线程[[NSOperationQueue mainQueue] addOperationWithBlock:^{//主线程操作}];}];
从其他线程回到主线程的方式
1.
perform...
1 [self performSelectorOnMainThread:<2.
GCD
123 dispatch_async(dispatch_get_main_queue(), ^{//主线程操作});3.NSOperationQueue
123 [[NSOperationQueue mainQueue] addOperationWithBlock:^{//主线程操作}];