iOS提供了三种多线程编程的方式:
iOS系统使用NSThread代表线程,创建新线程也就是创建NSThread对象,创建NSThread的方法有两种。
(1)-(id) initWithTarget:selector:object: //创建一个新线程对象;
<span style="font-size:14px;">// 创建线程对象
NSThread *thread = [[NSThread alloc]initWithTarget:self
selector:@selector(run) object:nil];
// 启动新线程
[thread start];</span>
(2)+(void) detachNewThreadSelector:toTarget:withObject: //创建并启动一个新线程(在OX10.5之前只能通过这种方式来启动一个线程)
<span style="font-size:14px;">// 创建并启动新线程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self
withObject:nil];</span>
以上两种方法的本质都是将target对象的selector方法转换成线程执行体。
NSOperationQueue:代表一个FIFO队列,负责管理系统提交的多个NSOperation,NSOperationQueue底层维护一个线程池,会按顺序启动线程来执行提交给该队列的NSOperation任务。
NSOperation:代表一个多线程任务,有两个子类:NSInvocationOperation和NSBlockOperation。创建NSOperation对象的方法有两种,一种是创建自定义类继承NSOperation,另一种是直接使用NSOperation的两个子类。
使用NSOperation与NSOperationQueue实现多线程分两步:
(1)创建NSOperationQueue队列,并为该队列设置属性;
<span style="font-size:14px;">NSOperationQueue* queue = [[NSOperationQueue alloc]init];
// 设置该队列最多支持10条并发线程
queue.maxConcurrentOperationCount = 10;</span>
(2)创建NSOperation子类对象,并将该对象提交给NSOperationQueue队列
<span style="font-size:14px;">// 将NSOperation的子类的实例提交给NSOperationQueue
[queue addOperation:operation];</span>
GCD的基本概念就是dispatch queue。dispatch queue是一个对象,它可以接受任务,并将任务以先到先执行的顺序来执行。dispatch queue可以是并发的或串行的,并发任务会像NSOperationQueue那样基于系统负载来合适地并发进行,串行队列同一时间只执行单一任务。关于GCD的具体描述请参考Apple官方文档。
GCD中有三种队列类型:main queue、global queues和用户队列。
(1)main queue:与主线程功能相同,提交至main queue的任务会在主线程中执行,mainqueue可以调用dispatch_get_main_queue() 来获得。因为main queue是与主线程相关的,所以这是一个串行队列。
(2)全局队列:是并发队列,并由整个进程共享。进程中存在四个全局队列:高、中(默认)、低和后台四个优先级队列,可以调用dispatch_get_global_queue()函数传入优先级来访问指定的全局队列。
(3)用户队列:是用函数 dispatch_queue_create() 创建的队列,是串行的,可以用来完成同步机制。这里需要注意的是,使用dispatch_queue_create() 创建的 dispatch queue 对象不受ARC机制的管理(全局队列和 main queue 不需要手动管理),需要手动进行内存管理,使用 dispatch_release 和 dispatch_retain 函数来操作引用计数。
使用GCD实现多线程也只有两步:
(1)创建队列;
(2)将任务提交给队列。
dispatch_async(提交异步任务)、dispatch_sync(提交同步任务)
向一个队列提交任务很简单:调用dispatch_async函数,传入一个队列和一个block。队列会在轮到这个block执行时执行这个block的代码。
如果希望在任务完成时更新UI界面,也就意味着需要在主线程中执行一些代码(UI操作必须在主线程中执行)。你可以简单地完成这个任务——使用嵌套的dispatch,在外层中执行后台任务,在内层中将任务dispatch到main queue。
<span style="font-size:14px;">dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self goDoSomethingLongAndInvolved];
dispatch_async(dispatch_get_main_queue(), ^{
[textField setStringValue:@"Done doing something long and involved"];
});
});</span>
假设有一段代码在后台执行,而它需要从界面控制层获取一个值,可以使用__block类型修饰符,从执行中的block中获取一个值。
使用嵌套的block来中止后台线程,然后从主线程中获取值,然后再将后期处理提交至后台线程。
<span style="font-size:14px;">dispatch_queue_t bgQueue = myQueue;
dispatch_async(dispatch_get_main_queue(), ^{
NSString *stringValue = [[[textField stringValue] copy] autorelease];
dispatch_async(bgQueue, ^{
// use stringValue in the background now
...
});
});</span>