iOS-四类多线程开发

前言

iOS开发中,多线程的使用其实已经被简化得很容易了。使用得最多的应该是GCD,一个函数就可以开线程,往队列中加任务。不过实际的工程开发中,大家涉及到的如果是界面开发的话,对于线程的认识就只停留在这一步了,仅仅是为了不阻塞主线程而开另一个线程来做一些耗时操作。
但是如果进行了一些网络方面的开发,比如网络下载,文件上传,则需要对多线程有深入一些的理解,至少会使用一些互斥锁来防止多个线程重复修改临界资源。
本文旨在罗列iOS中各类多线程编程的知识。其中GCD和NSOperation我使用得最熟悉。

四种方法

  • pthread
    linux底层接口,可以各平台通用,但是需要手动管理线程的生命周期,使用起来难度高
  • NSThread
    使用最多的是peformSelector以及currentThread
  • GCD
    基于底层接口的封装,不过还是C语言的接口。动不动就使用,任务和队列是重点。
  • NSOperation & NSOperationQueue
    基于GCD的封装,相比GCD有个特别明显的优点,那就是可以取消当前的操作,GCD是没办法取消的。

NSThread

初始化方法:

// 初始化线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(openThread:) object:nil];
// 开启线程
[thread start];

这时会调用openThread方法,这个方法就运行在thread这个线程中。

- (void)openThread:(id *)something {
NSThread *current = [NSThread currentThread];
NSLog(@"执行了openThread:方法,当前线程:%@", current);
}

还有其他开启线程的方法,比如
类方法开启

+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;

隐式创建

[self performSelectorInBackground:@selector(openThread:) withObject:nil];

阻塞当前线程

[NSThread sleepForTimeInterval:2];

在指定线程上执行操作

[self performSelector:@selector(openThread:) onThread:thread withObject:nil waitUntilDone:YES];

NSThread的开线程方式非常简单易用,系统已经帮我们省去了线程的创建、管理,销毁,我们只需要把注意力放在selector上,把指定任务的代码写完即可。

GCD

最重要的两个概念就是task和queue,任务和队列。你需要做的每一件事情就是一个任务。队列的存在让你可以执行多个任务。队列分串行队列和并行队列,串行就是每个任务按照先入先出挨个做,并行则不分先后一起做。
全局并发队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

主队列(串行)

dispatch_queue_t queue = dispatch_get_main_queue();

创建队列,第一个参数为队列名,第二个参数DISPATCH_QUEUE_SERIAL串行或DISPATCH_QUEUE_CONCURRENT并行

dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);

任务:同步执行
注意queue可以是串行或并行队列

dispatch_sync(queue, ^{
      //code here
      NSLog(@"%@", [NSThread currentThread]);
  });

任务:异步执行
注意queue可以是串行或并行队列

dispatch_async(queue, ^{
      //code here
      NSLog(@"%@", [NSThread currentThread]);
  });

NSOperation

  • NSInvocationOperation
    常见例子:initWithTarget: selector: object:,相当于performSelectorInBackground: withObject:
  • NSBlockOperation
    常见方法:blockOperationWithBlock:,addExecutionBlock:(这货竟然能并发)
  • 自定义Operation
    定制化的Operation,需要继承NSOperation以及覆写executing和finished

invocation和block的用法都非常简单,记住[operation start]方法会让operation同步执行即可,如果要让其异步执行可自己开线程或者加入到NSOperationQueue中。
对于自定义一个Operation,这里可以仔细说明一下。如果你的Operation不用并发,那覆写(override, 下同)一个main函数和初始化函数就可以了。
记得最开始写的时候,一直不明白,在并发Operation的情况下,为什么要覆写executing和finished,还要覆写main或者start函数。查过了那么多的文档,总算在官方文档找到。

iOS-四类多线程开发_第1张图片
需要覆写的方法.png
  • 覆写start是因为,自定义的Operation需要手动调用其start方法来开始执行这个operation。所以你必须覆写这个方法以致于替换掉原来的执行环境。还有记住不能调用[super start]
  • main方法是可选的,作用和start方法类似,如果不实现start方法,默认调用的是main。
  • executing和finish,operation有义务让调用者知道其执行的状态,所以操作执行的状态需要手动设置。
  • isConcurrent/isAsychronous 鉴别此operation是否为并发操作
    自定义Operation的代码这里就不给出来了,总之要自定义并发Operation的话就必须覆写上述几个方法。

NSOperationQueue

NSOperationQueue是设计来做NSOperation的并发操作用的,只要你调用了下面三个方法中的一个,你的Operation都会自动并发执行。

[aQueue addOperation:anOp]; 
[aQueue addOperations:anArrayOfOps waitUntilFinished:NO]; 
[aQueue addOperationWithBlock:^{ }];

需要留意的地方是,NSOperationQueue的cancelAllOperations方法,一旦调用,则会默认调用NSOperation的cancel,然后将其内部属性cancelled置为YES,如果这个Operation还未执行,那么有可能就被取消,而如果这个Operation正在执行中,那能不能取消,则结果未知。

你可能感兴趣的