美文网首页
iOS开发中多线程基本使用简介

iOS开发中多线程基本使用简介

作者: 这人很懒 | 来源:发表于2017-01-17 18:19 被阅读14次

一)NSThread 的使用

NSThread 有两种创建方式
第一种是实例方法,第二种是类方法:

- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument 
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];   

2、NSThread* myThread = [[NSThread alloc] initWithTarget:self   
                                        selector:@selector(doSomething:)   
                                        object:nil];   
[myThread start];

参数的意义:
selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
target :selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil

第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
不显示创建线程的方法:
用NSObject的类方法 performSelectorInBackground:withObject: 创建一个线程:

[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];

来个小例子

#import "ViewController.h"   
#define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"   
@interface ViewController ()   

@end   

@implementation ViewController   

-(void)downloadImage:(NSString *) url{   
    NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];   
    UIImage *image = [[UIImage alloc]initWithData:data];   
    if(image == nil){   

    }else{   
        [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];   
    }   
}   

-(void)updateUI:(UIImage*) image{   
    self.imageView.image = image;   
}   

- (void)viewDidLoad   
{   
    [super viewDidLoad];   

//    [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];   
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];   
    [thread start];   
}   

- (void)didReceiveMemoryWarning   
{   
    [super didReceiveMemoryWarning];   
    // Dispose of any resources that can be recreated.   
}   

@end

线程间通讯
现成下载完图片之后怎么通知主线程更新界面

[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];

performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:

performSelector:onThread:withObject:waitUntilDone:

NSThred 的简单使用就到这吧

二)Cocoa NSOperation

使用 NSOperation的方式有两种
一种是用定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。
另一种是继承NSOperation

如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似。和Java的Runnable一样,NSOperation也是设计用来扩展的,只需继承重写NSOperation的一个方法main。相当与java 中Runnalbe的Run方法。然后把NSOperation子类的对象放入NSOperationQueue队列中,该队列就会启动并开始处理它。
NSInvocationOperation例子

#import "ViewController.h"   
#define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"   

@interface ViewController ()   

@end   

@implementation ViewController   

- (void)viewDidLoad   
{   
    [super viewDidLoad];   
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self   
                                                                           selector:@selector(downloadImage:)   
                                                                             object:kURL];   

    NSOperationQueue *queue = [[NSOperationQueue alloc]init];   
    [queue addOperation:operation];   
    // Do any additional setup after loading the view, typically from a nib.   
}   

-(void)downloadImage:(NSString *)url{   
    NSLog(@"url:%@", url);   
    NSURL *nsUrl = [NSURL URLWithString:url];   
    NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];   
    UIImage * image = [[UIImage alloc]initWithData:data];   
    [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];   
}   
-(void)updateUI:(UIImage*) image{   
    self.imageView.image = image;   
}

代码注释
1.viewDidLoad方法里可以看到我们用NSInvocationOperation建了一个后台线程,并且放到2.NSOperationQueue中。后台线程执行downloadImage方法。
3.downloadImage 方法处理下载图片的逻辑。下载完成后用performSelectorOnMainThread执行主线程updateUI方法。
updateUI 并把下载的图片显示到图片控件中。

第二种方式继承 NSOperation
在.m文件中实现main方法,main方法编写要执行的代码即可。

如何控制线程池中的线程数
队列里可以加入很多个NSOperation, 可以把NSOperationQueue看作一个线程池,可往线程池中添加操作(NSOperation)到队列中。线程池中的线程可看作消费者,从队列中取走操作,并执行它。

通过下面的代码设置:

[queue setMaxConcurrentOperationCount:5];

线程池中的线程数,也就是并发操作数。默认情况下是-1,-1表示没有限制,这样会同时运行队列中的全部的操作。

三)GCD的介绍和使用

介绍
Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。
设计
GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。

一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。

GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行。

dispatch queue分为下面三种:
(Serial)
又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。
(Concurrent)
又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。
(Main dispatch queue )
它是全局可用的serial queue,它是在应用程序主线程上执行任务的。

1、常用的方法dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。

用GCD实现这个流程的操作比前面介绍的NSThread NSOperation的方法都要简单。代码框架结构如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   
    // 耗时的操作   
    dispatch_async(dispatch_get_main_queue(), ^{   
        // 更新界面   
    });   
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   
    NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];   
    NSData * data = [[NSData alloc]initWithContentsOfURL:url];   
    UIImage *image = [[UIImage alloc]initWithData:data];   
    if (data != nil) {   
        dispatch_async(dispatch_get_main_queue(), ^{   
            self.imageView.image = image;   
         });   
    }   
});

是不是代码比NSThread NSOperation简洁很多,而且GCD会自动根据任务在多核处理器上分配资源,优化程序。

系统给每一个应用程序提供了三个concurrent dispatch queues。这三个并发调度队列是全局的,它们只有优先级的不同。因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列,如下:

dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

这里也用到了系统默认就有一个串行队列main_queue:

dispatch_queue_t mainQ = dispatch_get_main_queue();

虽然dispatch queue是引用计数的对象,但是以上两个都是全局的队列,不用retain或release。

2、dispatch_group_async的使用
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);   
dispatch_group_t group = dispatch_group_create();   
dispatch_group_async(group, queue, ^{   
    [NSThread sleepForTimeInterval:1];   
    NSLog(@"group1");   
});   
dispatch_group_async(group, queue, ^{   
    [NSThread sleepForTimeInterval:2];   
    NSLog(@"group2");   
});   
dispatch_group_async(group, queue, ^{   
    [NSThread sleepForTimeInterval:3];   
    NSLog(@"group3");   
});   
dispatch_group_notify(group, dispatch_get_main_queue(), ^{   
    NSLog(@"updateUi");   
});   
dispatch_release(group);

dispatch_group_async是异步的方法,运行后可以看到打印结果:

2012-09-25 16:04:16.737 gcdTest[43328:11303] group1 
2012-09-25 16:04:17.738 gcdTest[43328:12a1b] group2 
2012-09-25 16:04:18.738 gcdTest[43328:13003] group3 
2012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi

3、dispatch_barrier_async的使用
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
例子代码如下:

dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);   
dispatch_async(queue, ^{   
    [NSThread sleepForTimeInterval:2];   
    NSLog(@"dispatch_async1");   
});   
dispatch_async(queue, ^{   
    [NSThread sleepForTimeInterval:4];   
    NSLog(@"dispatch_async2");   
});   
dispatch_barrier_async(queue, ^{   
    NSLog(@"dispatch_barrier_async");   
    [NSThread sleepForTimeInterval:4];   

});   
dispatch_async(queue, ^{   
    [NSThread sleepForTimeInterval:1];   
    NSLog(@"dispatch_async3");   
});

打印结果:请注意执行的时间,可以看到执行的顺序如上所述。

2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1 
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2 
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async 
2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3

4、dispatch_apply
执行某个代码片段N次。

dispatch_apply(5, globalQ, ^(size_t index) { 
    // 执行5次 
});

相关文章

  • iOS开发中多线程基本使用简介

    一)NSThread 的使用 NSThread 有两种创建方式第一种是实例方法,第二种是类方法: 参数的意义:se...

  • IOS---多线程实现方案一 (pthread、NSThrea

    IOS多线程实现方案一 (pthread、NSThread) 在iOS开发中,多线程是我们在开发中经常使用的一门技...

  • iOS多线程使用踩过的坑

    iOS多线程使用踩过的坑 iOS 开发过程中,我们经常使用系统提供的方法使用多线程(全局并发)包括: 使用起来很方...

  • iOS GCD的基本使用

    GCD在iOS中多线程开发中使用频繁,使用方便简单,可以满足我们大部分需求。其使用方法如下: 1、基本认识 GCD...

  • iOS 多线程(四)GCD

    一、GCD简介 iOS开发中多线程的API主要有pthread,NSThread,NSOperation和GC...

  • iOS多线程

    iOS多线程 iOS中多线程的方案?有什么优缺点? 技术方案简介语言线程生命周期使用频率pthread1.一套通用...

  • iOS多线程编程之GCD详解(一)

    1. GCD简介 iOS开发中多线程的API主要有pthread,NSThread,NSOperation和GCD...

  • iOS多线程--并行开发一

    iOS多线程--并行开发二 重点分析iOS多线程开发:iOS多线程:在iOS中每个进程启动后都会建立一个主线程(U...

  • pthread,NSThread的使用

    iOS中多线程的实现方案: 一、pthread的基本使用 pthread的基本使用(需要包含头文件) 二、NSTh...

  • iOS 关于多线程(GCD)

    一、关于iOS多线程的一些简单操作 链接地址:多线程简介 二、iOS开发多线程篇—GCD的常见用法 主要为:延迟执...

网友评论

      本文标题:iOS开发中多线程基本使用简介

      本文链接:https://www.haomeiwen.com/subject/ujombttx.html