Objective-C 多线程
iOS有三种多线程技术:
- 1.NSThread
- 创建方式两种:
- 1.实例方法:
- - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
- 先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
- 2.类方法:
- + (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
- 直接创建线程并开始运行线程
- 使用范例:
- [NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
- 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];
- 示范例子:(子线程异步下载,主线程UI更新)
- 创建方式两种:
#import "ViewController.h" #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg" @interface ViewController () @end @implementation ViewController - (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)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; } @end
- 2.NSOperation
- 用以封装执行程序中独立的工作单元,提供异步执行机制。
- NSOperation类为抽象类,基于模版方法设计模式
- Operations可以独立运行,也可以与Operation Queue协同运行。
- 使用方式有两种:
- 1.用定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。
- NSInvocationOperation:
- 创建方式:
- NSInvocationOperation* operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(customTaskMethod:)object:params];
- NSBlockOperation:
- 创建方式:
- NSBlockOperation* blockOperation = [NSBlockOperation blockOperationWithBlock: ^{
- // to do the task.
- }];
- 在创建blockOperation后可以调用addExecutionBlock:方法添加更多的block
- 示范例子:
#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; }
-
-
- 2.继承NSOperation
- 1.提供一个自定义的初始化方法,在执行operation之前提供初始化流程,准备operation状态
- 2.只需继承重写NSOperation的一个方法main
- 3.然后把NSOperation子类的对象放入NSOperationQueue队列中,该队列就会启动并开始处理它
- 示范例子:
- 2.继承NSOperation
-
@interface MoveFileOperation : NSOperation - (id)initWithSrcURL:(NSURL *)srcURL toDestinationURL:(NSURL*)desURL; @end // MoveFileOperation.m @interface MoveFileOperation () @property (retain) NSURL *srcURL; @property (retain) NSURL *desURL; @end @implementation MoveFileOperation @synthesize rootURL, queue; - (id)initWithSrcURL:(NSURL *)srcURL toDestinationURL:(NSURL*)desURL; { self = [super init]; if (self) { self.srcURL = srcURL; self.desURL = desURL; } return self; } - (void)main { if ([self isCancelled]){ return; } NSDirectoryEnumerator *itr =[[NSFileManager defaultManager] enumeratorAtURL:self.srcURL includingPropertiesForKeys:nil options:(NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants) errorHandler:nil]; NSError *error = [NSError new]; for (NSURL *url in itr) { if ([self isCancelled]) {// break; }else{ NSString *fileName = [url lastPathComponent]; NSURL *desFileURL = [self.desURL URLByAppendingPathComponent:fileName]; [[NSFileManager defaultManager] copyItemAtURL:url toURL:desFileURL error:&error]; } } }
-
-
-
- 通过isCancelled方法对operation支持线程取消行为:
- 常见的正确调用isCancelled的位置包括:
- 1.在实际执行工作之前
- 2.在每个循环的执行体中,如果一次执行体耗时很长可酌情添加调用次数
- 3.程序相对容易终止的代码处。
- 配置operation的依赖关系:
- 调用addDependency: 方法可以建立两个operation对象间的依赖关系:
- 这个单向关系表明当前operation对象只有在目标operation对象执行完成之后才能执行。
- operation对象的依赖关系不限于同一个操作队列。
- 有依赖关系的operation对象可以添加到不同的操作队列中。
- 但是operation之间不能添加循环依赖关系。
- 添加Completion Block:
- 通过setCompletionBlock: 方法可以完成添加completion block的工作,可以在此处派发operation完成的消息。
- 执行operation的方式:
- 1 .将operation对象添加到操作队列NSOperatinQueue对象中:
- NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
- 1.// Add a single operation
- [aQueue addOperation:anOp];
- 2.// Add multiple operations
- [aQueue addOperations:anArrayOfOps waitUntilFinished:NO];
- 3.// Add a block
- [aQueue addOperationWithBlock:^{
- /* Do something. */
- }];
- NSOperationQueue设计上是用来并发执行operation,setMaxConcurrentOperationCount:方法可以设置操作队列并行执行的最大数量。
- 需要设置operation间的依赖关系来保证它们的执行顺序是你想要的。
- 2.手动执行operation:
- 一个operation只有在其isReady方法返回YES时才被认为是可运行的。
- isReady方法会被整合进NSOperation的依赖管理系统来保证operation的依赖状态。
- 只有在依赖关系清楚后,operation才开始运行。
- 手动执行operation时,必须调用其start方法。
- 1 .将operation对象添加到操作队列NSOperatinQueue对象中:
- 取消operation:
- 一旦加入操作队列,操作队列就拥有了该operation,并且它不能被删除。
- 调出operation的唯一方法是取消(cancel)它
- 在一个operation上调用cancel可以取消其执行,在操作队列对象上调用cancelAllOperations 会取消所有operation。
- operation的取消行为也会被认为是执行完毕(finished),依赖于它的其它operation对象会收到KVO通知来清除该依赖关系。
- 等待operation结束:
- 如果创建operation的进程需要处理operation的结果,可以使用NSOperation的 waitUntilFinished方法来阻塞代码直到operation完成(决不能在主线程上等待一个operation结束)
- 挂起和回复队列:
- 调用NSOperationQueue对象的setSuspended: 方法可以操作队列挂起。挂起队列不会阻碍当前正在执行中的operation,它只是阻止新的operation的执行。
-
-
- 3.GCD