在iOS开发中,所有UI的更新工作,都必须在主线程上执行!
除非将程序杀掉,否则主线程的工作永远不会结束!
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);
// 非ARC开发时,千万别忘记release
// dispatch_release(q);
串行队列: 同步<在一个线程(主线程)上顺序执行> 异步<会新建一个子线程,顺序执行>
并行队列: 同步<在一个线程(主线程)上顺序执行> 异步<会新建多个子线程,无序执行>
全局队列: 是一个并行队列
主队列: 是一个串行队列(做同步操作会死锁)
队列的特点是先进先出,负责调度任务在哪个线程上执行,以及执行的时间
在串行队列的同步操作中嵌套同步操作会导致死锁,嵌套之前的代码会执行
主队列中添加的同步操作永远不会被执行,会死锁,因为同步任务会一直等待主线程结束
无论什么队列和什么任务,线程的创建和回收不需要程序员参与。
线程的创建回收工作是由队列负责的
不能将一个操作添加到多个队列中
自定义队列添加的任务,相当于GCD的并行队列,异步任务
[self.myQueue addOperation:op];
添加依赖 [op4 addDependency:op3];
// 在iOS中,GCD和NSOperation新建线程时,会自动在新线程中创建自动释放池
// 但是,使用NSThread的时候,系统不会自动创建自动释放池
// 在使用NSThread以及NSObject封装的多线程方法,如果涉及到对象的分配,需要手动添加autoreleasepool,否则会出现内存泄露
@autoreleasepool {
NSLog(@"%@", [NSThread currentThread]);
// [NSThread sleepForTimeInterval:2.0f]; 休眠2秒
// waitUntilDone = YES表示等待selector方法执行完毕
[self performSelectorOnMainThread:@selector(setImage:) withObject:[UIImage imageNamed:imageName] waitUntilDone:NO];
}
实际运用中,一般可以这样来写,常见的网络请求数据多线程执行模型:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//子线程中开始网络请求数据
//更新数据模型
dispatch_sync(dispatch_get_main_queue(), ^{
//在主线程中更新UI代码
});
});
程序的后台运行和UI更新代码紧凑,代码逻辑一目了然。
所有的自定义队列,都是在子线程上运行的
操作依赖:
[op2 addDependency:op1];
单例的实现步骤:
+ (id)allocWithZone:(struct _NSZone *)zone
{
static Ticket *instance;
static dispatch_once_t onceToken;
//dispatch_once是线程安全的,能够做到在多线程的环境下Block中的代码只会被执行一次
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}