iOS多线程编程

龚浩宕
2023-12-01

iOS提供了三种多线程编程的方式:

  • 使用NSThread实现多线程;
  • 使用NSOperation与NSOperationQueue实现多线程;
  • 使用GCD实现多线程实现多线程。

一、使用NSThread实现多线程

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方法转换成线程执行体。

二、使用NSOperation与NSOperationQueue实现多线程

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实现多线程实现多线程

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>

 类似资料: