线程的注意点
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)先创建,后启动
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:nil];
// 启动
[thread start];
(2)创建完自动启动
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:nil];
(3)隐式创建(自动启动)
[self performSelectorInBackground:@selector(download:) withObject:nil];
2.常见方法
(1)获得当前线程
+ (NSThread *)currentThread;
(2)获得主线程
+ (NSThread *)mainThread;
(3)睡眠(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
(4)设置线程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
线程同步
1.实质:为了防止多个线程抢夺同一个资源造成的数据安全问题
2.实现:给代码加一个互斥锁(同步锁)
@synchronized(self) {
// 被锁住的代码
}
GCD(Grand Central Dispatch)
1.队列和任务
(1) 任务 :需要执行什么操作
- 用block来封装任务
(2)队列 :存放任务
- 全局的并发队列 : 可以让任务并发执行
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- 自己创建的串行队列 : 让任务一个接着一个执行
dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue", NULL);
- 主队列 : 让任务在主线程执行
dispatch_queue_t queue = dispatch_get_main_queue();
2.执行任务的函数
(1)同步执行 : 不具备开启新线程的能力
dispatch_sync...
(2)异步执行 : 具备开启新线程的能力
dispatch_async...
3.常见的组合
(1)dispatch_async
+ 全局并发队列
(2)dispatch_async
+ 自己创建的串行队列
4.线程间的通信
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....
// 3秒后自动回到当前线程调用self的download:方法,并且传递参数:@"http://555.jpg"
[self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];
(2) dispatch_after...
// 任务放到哪个队列中执行
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.一次性代码
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 这里面的代码,在程序运行过程中,永远只会执行1次
});
单例模式(懒汉式)
1.ARC
@interface HMDataTool : NSObject
+ (instancetype)sharedDataTool;
@end
@implementation HMDataTool
// 用来保存唯一的单例对象
static id _instace;
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});
return _instace;
}
+ (instancetype)sharedDataTool
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [[self alloc] init];
});
return _instace;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instace;
}
@end
MRC
@interface HMDataTool : NSObject
+ (instancetype)sharedDataTool;
@end
@implementation HMDataTool
// 用来保存唯一的单例对象
static id _instace;
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});
return _instace;
}
+ (instancetype)sharedDataTool
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [[self alloc] init];
});
return _instace;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instace;
}
- (oneway void)release {
}
- (id)retain {
return self;
}
- (NSUInteger)retainCount {
return 1;
}
- (id)autorelease {
return self;
}
@end
NSOperation和NSOperationQueue
1.队列的类型
(1) 主队列
[NSOperationQueue mainQueue]
添加到"主队列"中的操作,都会放到主线程中执行
(2) 非主队列
[[NSOperationQueue alloc] init]
添加到"非主队列"中的操作,都会放到子线程中执行
2.队列添加任务
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
3.常见用法
(1) 设置最大并发数
- (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.线程之间的通信
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// 1.执行一些比较耗时的操作
// 2.回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//主线程操作
}];
}];
从其他线程回到主线程的方式
1.perform...
[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
2.GCD
dispatch_async(dispatch_get_main_queue(), ^{
//主线程操作
});
3.NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//主线程操作
}];
网友评论