Objective-C提供了多种不同的异步处理方式,这里主要看3种比较常用的方式:NSThread、Grand Central Dispatch与NSOperationQueue。
一、NSThread
NSThread是OC提供的线程类,基于此,我们可以很方便地开辟线程。在OS X V10.5之前,该类只提供了一种开启新线程的方法(如:
- [NSThread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil]
- NSThread *thread=[[[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil] autorelease];
- [thread start];
另外 ,内存管理对于线程来说非常重要。需要将task方法的代码放到autoreleasepool中。在非GC项目中,OC可以凭借autoreleasepool使用内存资源,然后在需要的时候回收资源。每个线程都需要有autoreleasepool,否则应用中会出现内存泄露。
二、主线程与后台线程通信
NSObject类提供了performSelectorOnMainThread:withObject:waitUntilDone:方法用执行主线程中方法。我们可以通过这个方法从后台线程通知主线程做一些界面处理。这里说明一下,该方法最后一个参数是一个BOOL值。如果是YES,则表示当前线程会阻塞,直到指定的任务在主线程中执行完;如果是NO,则不阻塞当前线程。
三、线程同步
我们可以使用NSLock锁定线程,然后在任务执行完后再解锁。如:
- -(void)task
- {
- [threadLock lock];
- @autoreleasepool {
- ... ...
- }
- [threadLock unlock];
- }
除了NSLock,我们还可以使用@synchronized关键字。@synchronized与NSLock解决的都是同样的线程问题,但实现方式不同,@synchronized可以处理异常。此外,@synchronized方式要比NSLock具备更好的性能。
四、GCD
GCD技术在OSX 10.6与IOS 4中被引入,其针对多核应用进行了优化,在拥有多个处理器的计算机上应用的性能会极大提升。GCD的出现减轻了再多核上编程的负担,也减少了不少线程管理的麻烦。GCD是一个系统级别的技术,因此我们可以在任意级别的代码中使用它。GCD决定需要多少线程并安排它们的运行进度。因为它是运行在系统级别上得,所以可以平衡应用程序所有内容的加载。
1、添加任务的方式
有两种方式可以向队列中添加任务。
同步:队列会一直等待前面的任务结束。
异步:添加后,不必等待任务结束,函数会立即返回。推荐优先使用这种方式,因为它不会阻塞其他任务的执行。
2、调度队列
GCD使用调度队列(dispatch queue),它与线程很相似但使用起来更简单。只需要将任务添加到队列中,系统就会执行它。一共有以下3种类型的队列。
连续队列:每个连续队列都会根据指派的顺序执行任务。我们可以按自己的想法创建多个连续队列,它们会并行操作任务。有时候有一串任务需要按照一定的顺序执行,这时便可以使用连续队列,任务执行的顺序为先入先出(FIFO)。
(1)异步添加任务
- dispatch_queue_t serial_queue= dispatch_queue_create("com.jerry.SerialQueue", NULL);
- dispatch_async(serial_queue, ^{
- for(int i=0;i<100;i++){
- NSLog(@"task::111-------%i",i);
- }
- });
- NSLog(@"dispatched task 111");
- dispatch_async(serial_queue, ^{
- for(int i=0;i<100;i++){
- NSLog(@"task::222-------%i",i);
- }
- });
- NSLog(@"dispatched task 222");
- dispatch_async(serial_queue, ^{
- for(int i=0;i<100;i++){
- NSLog(@"task::333-------%i",i);
- }
- });
- NSLog(@"dispatched task 333");
下面是执行结果(由于输出内容太长,这里只截取部分):