NSOperation
一、NSOperation
1.简介
NSOperation实例封装了需要执行的操作和执行操作所需的数据,并且能够以并发或非并发的方式执行这个操作。
NSOperation本身是抽象基类,因此必须使用它的子类,使用NSOperation子类的方式有2种:
1> Foundation框架提供了两个具体子类直接供我们使用:NSInvocationOperation和NSBlockOperation
2> 自定义子类继承NSOperation,实现内部相应的方法
2.执行操作
NSOperation调用start方法即可开始执行操作,NSOperation对象默认按同步方式执行,也就是在调用start方法的那个线程中直接执行。NSOperation对象的isConcurrent方法会告诉我们这个操作相对于调用start方法的线程,是同步还是异步执行。isConcurrent方法默认返回NO,表示操作与调用线程同步执行
3.取消操作
operation开始执行之后, 默认会一直执行操作直到完成,我们也可以调用cancel方法中途取消操作
[operation cancel];
operation.completionBlock = ^() { NSLog(@"执行完毕"); };
[operation setCompletionBlock:^() { NSLog(@"执行完毕"); }];
2.创建并执行操作
// 这个操作是:调用self的run方法 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; // 开始执行任务(同步执行) [operation start];
2.创建并执行操作
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行了一个新的操作,线程:%@", [NSThread currentThread]); }]; // 开始执行任务(这里还是同步执行) [operation start];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]); }]; [operation addExecutionBlock:^() { NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]); }]; [operation addExecutionBlock:^() { NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]); }]; [operation addExecutionBlock:^() { NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]); }]; // 开始执行任务 [operation start];
2013-02-02 21:38:46.102 thread[4602:c07] 又执行了1个新的操作,线程:<NSThread: 0x7121d50>{name = (null), num = 1} 2013-02-02 21:38:46.102 thread[4602:3f03] 又执行了1个新的操作,线程:<NSThread: 0x742e1d0>{name = (null), num = 5} 2013-02-02 21:38:46.102 thread[4602:1b03] 执行第1次操作,线程:<NSThread: 0x742de50>{name = (null), num = 3} 2013-02-02 21:38:46.102 thread[4602:1303] 又执行了1个新的操作,线程:<NSThread: 0x7157bf0>{name = (null), num = 4}
可以看出,这4个block是并发执行的,也就是在不同线程中执行的,num属性可以看成是线程的id
四、自定义NSOperation
1.简介
如果NSInvocationOperation和NSBlockOperation对象不能满足需求, 你可以直接继承NSOperation, 并添加任何你想要的行为。继承所需的工作量主要取决于你要实现非并发还是并发的NSOperation。定义非并发的NSOperation要简单许多,只需要重载-(void)main这个方法,在这个方法里面执行主任务,并正确地响应取消事件; 对于并发NSOperation, 你必须重写NSOperation的多个基本方法进行实现(这里暂时先介绍非并发的NSOperation)
2.非并发的NSOperation
比如叫做DownloadOperation,用来下载图片
1> 继承NSOperation,重写main方法,执行主任务
DownloadOperation.h
#import <Foundation/Foundation.h> @protocol DownloadOperationDelegate; @interface DownloadOperation : NSOperation // 图片的url路径 @property (nonatomic, copy) NSString *imageUrl; // 代理 @property (nonatomic, retain) id<DownloadOperationDelegate> delegate; - (id)initWithUrl:(NSString *)url delegate:(id<DownloadOperationDelegate>)delegate; @end
// 图片下载的协议 @protocol DownloadOperationDelegate <NSObject> - (void)downloadFinishWithImage:(UIImage *)image; @end
#import "DownloadOperation.h" @implementation DownloadOperation @synthesize delegate = _delegate; @synthesize imageUrl = _imageUrl; // 初始化 - (id)initWithUrl:(NSString *)url delegate:(id<DownloadOperationDelegate>)delegate { if (self = [super init]) { self.imageUrl = url; self.delegate = delegate; } return self; } // 释放内存 - (void)dealloc { [super dealloc]; [_delegate release]; [_imageUrl release]; } // 执行主任务 - (void)main { // 新建一个自动释放池,如果是异步执行操作,那么将无法访问到主线程的自动释放池 @autoreleasepool { // .... } } @end
- (void)main { // 新建一个自动释放池,如果是异步执行操作,那么将无法访问到主线程的自动释放池 @autoreleasepool { if (self.isCancelled) return; // 获取图片数据 NSURL *url = [NSURL URLWithString:self.imageUrl]; NSData *imageData = [NSData dataWithContentsOfURL:url]; if (self.isCancelled) { url = nil; imageData = nil; return; } // 初始化图片 UIImage *image = [UIImage imageWithData:imageData]; if (self.isCancelled) { image = nil; return; } if ([self.delegate respondsToSelector:@selector(downloadFinishWithImage:)]) { // 把图片数据传回到主线程 [(NSObject *)self.delegate performSelectorOnMainThread:@selector(downloadFinishWithImage:) withObject:image waitUntilDone:NO]; } } }
NSOperationQueue
一、简介
一个NSOperation对象可以通过调用start方法来执行任务,默认是同步执行的。也可以将NSOperation添加到一个NSOperationQueue(操作队列)中去执行,而且是异步执行的。
创建一个操作队列:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
[queue addOperations:operations waitUntilFinished:NO];
[queue addOperationWithBlock:^() { NSLog(@"执行一个新的操作,线程:%@", [NSThread currentThread]); }];
三、添加NSOperation的依赖对象
1.当某个NSOperation对象依赖于其它NSOperation对象的完成时,就可以通过addDependency方法添加一个或者多个依赖的对象,只有所有依赖的对象都已经完成操作,当前NSOperation对象才会开始执行操作。另外,通过removeDependency方法来删除依赖对象。
[operation2 addDependency:operation1];
唯一的限制是不能创建环形依赖,比如A依赖B,B依赖A,这是错误的
2.依赖关系会影响到NSOperation对象在queue中的执行顺序,看下面的例子:
1> 没有设置依赖关系
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第2次操作,线程:%@", [NSThread currentThread]); }]; [queue addOperation:operation1]; [queue addOperation:operation2];
2013-02-03 00:21:35.024 thread[5616:3d13] 执行第1次操作,线程:<NSThread: 0x7658570>{name = (null), num = 3} 2013-02-03 00:21:35.063 thread[5616:1303] 执行第2次操作,线程:<NSThread: 0x765a2e0>{name = (null), num = 4}
可以看出,默认是按照添加顺序执行的,先执行operation1,再执行operation2
2> 设置了依赖关系
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"执行第2次操作,线程:%@", [NSThread currentThread]); }]; // operation1依赖于operation2 [operation1 addDependency:operation2]; [queue addOperation:operation1]; [queue addOperation:operation2];
2013-02-03 00:24:16.260 thread[5656:1b03] 执行第2次操作,线程:<NSThread: 0x7634490>{name = (null), num = 3} 2013-02-03 00:24:16.285 thread[5656:1303] 执行第1次操作,线程:<NSThread: 0x9138b50>{name = (null), num = 4}
可以看出,先执行operation2,再执行operation1
四、修改Operations的执行顺序
对于添加到queue中的operations,它们的执行顺序取决于2点:
1.首先看看NSOperation是否已经准备好:是否准备好由对象的依赖关系确定
2.然后再根据所有NSOperation的相对优先级来确定。优先级等级则是operation对象本身的一个属性。默认所有operation都拥有“普通”优先级,不过可以通过setQueuePriority:方法来提升或降低operation对象的优先级。优先级只能应用于相同queue中的operations。如果应用有多个operation queue,每个queue的优先级等级是互相独立的。因此不同queue中的低优先级操作仍然可能比高优先级操作更早执行。
注意:优先级不能替代依赖关系,优先级只是对已经准备好的 operations确定执行顺序。先满足依赖关系,然后再根据优先级从所有准备好的操作中选择优先级最高的那个执行。
五、设置队列的最大并发操作数量
队列的最大并发操作数量,意思是队列中最多同时运行几条线程
虽然NSOperationQueue类设计用于并发执行Operations,你也可以强制单个queue一次只能执行一个Operation。setMaxConcurrentOperationCount:方法可以配置queue的最大并发操作数量。设为1就表示queue每次只能执行一个操作。不过operation执行的顺序仍然依赖于其它因素,比如operation是否准备好和operation的优先级等。因此串行化的operation queue并不等同于GCD中的串行dispatch queue
// 每次只能执行一个操作 queue.maxConcurrentOperationCount = 1; // 或者这样写 [queue setMaxConcurrentOperationCount:1];
// 取消单个操作 [operation cancel]; // 取消queue中所有的操作 [queue cancelAllOperations];
// 会阻塞当前线程,等到某个operation执行完毕 [operation waitUntilFinished];
// 阻塞当前线程,等待queue的所有操作执行完毕 [queue waitUntilAllOperationsAreFinished];
// 暂停queue [queue setSuspended:YES]; // 继续queue [queue setSuspended:NO];
本文向大家介绍iOS多线程应用开发中使用NSOperation类的基本方法,包括了iOS多线程应用开发中使用NSOperation类的基本方法的使用技巧和注意事项,需要的朋友参考一下 一、NSOperation简介 1.简单说明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue
主要内容:Objective-C令牌,分号;,注释,标识符,关键字,Objective-C空白格前面已经看到了Objective-C程序的基本结构,因此很容易理解Objective-C编程语言的其他基本构建块。 Objective-C令牌 Objective-C程序由各种令牌组成,令牌可以是关键字,标识符,常量,字符串文字或符号。 例如,以下Objective-C语句由六个令牌组成 - 单个标记是 - 分号; 在Objective-C程序中,分号是语句终止符。也就是说,每个单独的语句必须以分
本文向大家介绍C#多线程编程中的锁系统基本用法,包括了C#多线程编程中的锁系统基本用法的使用技巧和注意事项,需要的朋友参考一下 平常在多线程开发中,总避免不了线程同步。本篇就对net多线程中的锁系统做个简单描述。 目录 一:lock、Monitor 1:基础。 2: 作用域。 3:字符串锁。 4:monitor使用 二:mutex 三:Semaphore 四
下面的代码应该从用户那里获取两个整数(每个输入一个线程),将它们相加(使用第三个线程)并打印总和。但是程序在第一个线程之后终止。 它给出的输出:
本教程提供了 Objective-C 程序员如何使用 gRPC 的指南。通过学习教程中例子,你可以学会如何: 在一个 .proto 文件内定义服务。 用 protocol buffer 编译器生成客户端代码。 使用 gRPC 的 Objective-C API 为你的服务实现一个简单的客户端。 假设你已经熟悉了protocol buffers。 注意,教程中的例子使用的是 protocol buf
主要内容:1. 指针是什么?,2. 如何使用指针?,3. Objective-C NULL指针,4. Objective-C指针详解Objective-C中的指针简单易学。使用指针可以更轻松地执行某些Objective-C编程任务,并且在不使用指针的情况下无法执行其他任务(如动态内存分配)。 所以有必要学习指向成为一个完美的Objective-C程序员。在这小节中将通过简单的步骤学习指针。 每个变量都是一个内存位置,每个内存位置都定义了它的地址,可以使用符号()运算符进行访问,该运算符表示内存中