在项目开发中,一个进程默认情况下,只有一个线程,也就是我们说的主线程。如果我们把所有的操作都在主线程中进行的话,很有可能会造成主线程堵塞,界面很卡,给用户很不好的体验效果。比较我们进入一个界面需要网络请求时,假如这个请求要十秒钟才能请求下来,如果这些都在主线程中进行的话,那这10秒钟我们就只能干看着手机,就连返回都不能,很显然,这样的应用时太坑爹了的。所以就需要我们手动来创建一个或者多个线程,来分担主线程的繁重的任务。
iOS现在创建线程,多线程操作的方式一共有三种:NSThread、NSOperation、GCD。废话不多说,进入正题。下面就是这三种线程一些简单的介绍。
一 NSThread方式创建线程
两种方式创建:
1.[NSThreaddetachNewThreadSelector:@selector(doSomething2:) toTarget:self withObject:@”传的参数”];
2.NSThread *myThread =[[NSThread alloc] initWithTarget:self selector:@selector(doSomething2:)object:@”参数”];
[myThread start];
//只有start的之后,线程才会正式启动。
NSThread方式进行多线程操作时,多个线程时必须上锁NSLock,在一个线程完成操作后解锁[theLock unlock];
通过NSCondition的signal方法,发送信号的方式,在这个线程中唤醒另外一个线程的等待
二 NSOperationQueue和NSOperation
通过NSOperationQueue建立一个线程管理器,建立过程:
建立NSOperationQueue对象→建立NSOperation对象→将NSOperation对象加入到队列中→release掉NSOperation对象(非ARC下)
NSOperation对象通过NSInvocationOperation类建立,是NSOperation的子类
NSOperationQueue通过setMaxConcurrentOperationCount方法设定队列中线程的个数
创建方法:
NSOperationQueue *queue= [NSOperationQueue new];
NSInvocationOperation*operation = [[NSInvocationOperation alloc] initWithTarget:selfselector:@selector(doSomething:) object:@”传的参数是个字符串”];
[queueaddOperation:operation];
//运行在另外一个线程
- (void)doSomething:(NSString *)string{
NSLog(@”%@”,string);
}
三 GCD
GCD:Grand Central Dispatch 是Apple开发的一个多核编程的解决方法。和block一起使用,使用最方便。
#pragma mark - 系统方法的GCD
/*
dispatch_async开启一个异步请求
第一个参数是指定一个gcd队列,第二个参数是分配一个处理事物的程序块到该队列
dispatch_get_global_queue指定为全局队列
第一个参数是分配事物处理程序的块队列优先级。
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
- (void)GCDwaysOne{
//后台执行
dispatch_async(dispatch_get_global_queue(0,0), ^{
//something
});
//主线程执行
dispatch_async(dispatch_get_main_queue(), ^{
//something
});
//一次性执行
staticdispatch_once_t
dispatch_once(&onceToken, ^{
//something
});
//延迟1秒执行
double delayOne =1.0;
dispatch_time_t time =dispatch_time(DISPATCH_TIME_NOW, delayOne *NSEC_PER_SEC);
dispatch_after(time,dispatch_get_main_queue(), ^{
});
}
#pragma mark - 自定义dispatch_queue_t
- (void)GCDwaysTwo{
//自定义的dispatch_queue_t
dispatch_queue_t url_queue =dispatch_queue_create("something",NULL);
dispatch_async(url_queue, ^{
//something
//非arc下需要释放
//dispatch_release(url_queue);
}
#pragma mark - 后台多线程并发
/*
异步和并发的不同点:
异步只是提供了一种多线程处理的概念,
并发是更像是异步的一种大规模实现
*/
- (void)GCDwaysThree{
dispatch_group_t group =dispatch_group_create();
dispatch_group_async(group,dispatch_get_global_queue(0,0), ^{
//并行执行的线程一
});
dispatch_group_async(group,dispatch_get_global_queue(0,0), ^{
//并行执行的线程二
});
dispatch_group_notify(group,dispatch_get_global_queue(0,0), ^{
//汇总结果
});
}
这里我对三种方式创建多线程也做了一下总结,关于他们各自的优缺点。
优点:
NSThread:相比其它两种方式更加轻量,使用简单。
NSOperation:不需要关心线程管理,数据同步的事情;
NSOperationQueue可以添加依赖,让一个线程在另一个完成后才执行,没有上锁解锁这些繁琐的操作;
(NSOperation是基于OC实现的,所以是面向对象的创建线程的技术,网络请求的时候第三方框架,AFNetworking就是直接用的NSOperation)
GCD:抽象度是最高的,使用也就越简单,是Apple最推荐使用,基于C语言的框架开发的。而且GCD使用时,会与block结合起来用,比较简便高效。并且GCD能够在“多核”上使用多线程。
缺点:
NSThread:需要自己管理线程的生命周期,线程同步。线程同步对数据枷锁会有一定的系统开销。
注:所有创建的子线程都不能对UI进行操作,需回到主线程。例:网络请求完成后需要刷新界面就必须回到主线程。