IOS学习之路七(使用 Operation 异步运行任务)

来源:互联网 发布:京东分析与数据库 编辑:程序博客网 时间:2024/06/06 05:54

application delegate头文件(.h)中声明一个operation队列和两个 invocation operations

#import <UIKit/UIKit.h>@interface Running_Tasks_Asynchronously_with_OperationsAppDelegate: UIResponder <UIApplicationDelegate> @property (nonatomic, strong) UIWindow *window;@property (nonatomic, strong) NSOperationQueue *operationQueue; @property (nonatomic, strong) NSInvocationOperation *firstOperation; @property (nonatomic, strong) NSInvocationOperation *secondOperation; @end

application delegate的实现文件(.m文件)如下: 

#import "Running_Tasks_Asynchronously_with_OperationsAppDelegate.h" @implementation Running_Tasks_Asynchronously_with_OperationsAppDelegate @synthesize window = _window;@synthesize firstOperation;@synthesize secondOperation;@synthesize operationQueue;- (void) firstOperationEntry:(id)paramObject{NSLog(@"%s", __FUNCTION__);NSLog(@"Parameter Object = %@", paramObject); NSLog(@"Main Thread = %@", [NSThread mainThread]); NSLog(@"Current Thread = %@", [NSThread currentThread]);}- (void) secondOperationEntry:(id)paramObject{NSLog(@"%s", __FUNCTION__);NSLog(@"Parameter Object = %@", paramObject); NSLog(@"Main Thread = %@", [NSThread mainThread]); NSLog(@"Current Thread = %@", [NSThread currentThread]);}- (BOOL) application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions{NSNumber *firstNumber = [NSNumber numberWithInteger:111]; NSNumber *secondNumber = [NSNumber numberWithInteger:222];self.firstOperation =[[NSInvocationOperation alloc] initWithTarget:selfselector:@selector(firstOperationEntry:)object:firstNumber]; self.secondOperation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(secondOperationEntry:) object:secondNumber];self.operationQueue = [[NSOperationQueue alloc] init]; /* Add the operations to the queue */[self.operationQueue addOperation:self.firstOperation]; [self.operationQueue addOperation:self.secondOperation];NSLog(@"Main thread is here");self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible];return YES;} @end

在实现的代码里面都发生了什么呢:
有两个方法:firstOperationEntry:secondOperationEntry:,每个方法都接收一个对象 

作为参数,并且在控制台窗口打印出当前线程、主线程和参数。这两个入口函数的

invocation operation将被添加到一个 operation队列中。
我们初始化两个NSInvocationOperation类型对象,并给每个 operation设置目标

selector 入口点,如之前所述。
然后我们初始化一个NSOperationQueue类型对象。(当然也可以在入口方法前面创

建)队列对象将负责管理 operation对象的并发。
我们调用NSOperationQueue的实例方法 addOperation:把每个invocation operation添加

operation队列中。在这里,operation队列可能会也可能不会立即通过 nvocationoperationstart方法启动 invocation operation。但是,需要牢记重要的一点:添加operationsoperation队列后,你不能手动启动 operations,必须交由operation队列负责。

现在,我们运行一次示例代码,在控制台窗口可以看到如下结果:

[Running_Tasks_Asynchronously_with_OperationsAppDelegate firstOperationEntry:]Main thread is here
Parameter Object = 111
[Running_Tasks_Asynchronously_with_OperationsAppDelegate secondOperationEntry:]Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}

Parameter Object = 222
Current Thread = <NSThread: 0x6805c20>{name = (null), num = 3}Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}Current Thread = <NSThread: 0x6b2d1d0>{name = (null), num = 4} 


如果我们子类化了一个 NSOperation类,并且把这个子类的实例对象添加到了 operation队列,我们需要做稍微的改动。记住以下几点:

由于当把NSOperation的子类对象添加到一个 operation队列中,该对象会异步运行。由此,你必须 overrideNSOperation的实例方法 isConcurrent,在该方法中返回YESstart方法里面执行 main任务之前,需要定期的调用 isCancelled方法来检测该函数的返回值,以确定是退出 start方法还是开始运行 operation。在这里,当operation添加到队列中后,operationstart方法将会被 operation队列调用,start方法中,调用isCanelled方法确定 operation是否被取消。如果 operation被取消了,只需要从 start 

方法中简单的返回即可。如果没被取消,会在 start方法中调用 main方法。

main task实现部分中 override main函数,main函数将被 operation执行。在这个函数里面确保分配和初始化 autorelease pool,并且在返回之前释放这个pool

重载operationisFinishedisExecuting方法,这两个函数返回对应的 BOOL值,代表 operation是执行完毕还是在执行中。

下面是我们的 operation声明(.h文件)

#import <Foundation/Foundation.h>@interface SimpleOperation : NSOperation/* Designated Initializer */- (id) initWithObject:(NSObject *)paramObject; @endThe implementation of the operation is as follows:#import "SimpleOperation.h" @implementation SimpleOperation NSObject *givenObject;BOOL finished;BOOL executing;- (id) init {NSNumber *dummyObject = [NSNumber numberWithInteger:123]; return([self initWithObject:dummyObject]);}- (id) initWithObject:(NSObject *)paramObject{self = [super init];if (self != nil){/* Keep these values for the main method */givenObject = paramObject;}return(self);}- (void) start {/* If we are cancelled before starting, thenwe have to return immediately and generate therequired KVO notifications */if ([self isCancelled]){/* If this operation *is* cancelled *//* KVO compliance */[self willChangeValueForKey:@"isFinished"];finished = YES;[self didChangeValueForKey:@"isFinished"];return;} else {/* If this operation is *not* cancelled *//* KVO compliance */[self willChangeValueForKey:@"isExecuting"]; executing = YES;/* Call the main method from inside the start method */ [self main];[self didChangeValueForKey:@"isExecuting"];}}- (void) main {@try {@autoreleasepool {/* Keep a local variable here that must get set to YES whenever we are done with the task */
BOOL taskIsFinished = NO;/* Create a while loop here that only existsif the taskIsFinished variable is set to YES orthe operation has been cancelled */while (taskIsFinished == NO &&[self isCancelled] == NO){/* Perform the task here */NSLog(@"%s", __FUNCTION__);NSLog(@"Parameter Object = %@", givenObject); NSLog(@"Main Thread = %@", [NSThread mainThread]); NSLog(@"Current Thread = %@", [NSThread currentThread]); /* Very important. This way we can get out of theloop and we are still complying with the cancellationrules of operations */taskIsFinished = YES;}/* KVO compliance. Generate therequired KVO notifications */[self willChangeValueForKey:@"isFinished"]; [self willChangeValueForKey:@"isExecuting"]; finished = YES;executing = NO;[self didChangeValueForKey:@"isFinished"]; [self didChangeValueForKey:@"isExecuting"]; }}@catch (NSException * e) { NSLog(@"Exception %@", e);}}- (BOOL) isConcurrent{return YES;}- (BOOL) isFinished{/* Simply return the value */return finished;}- (BOOL) isExecuting{/* Simply return the value */return executing;}@end

现在可以在其他任何类中使用上面定义的这个 operation类了,比如在 applicationdelegate中。下面是 application delegate的声明,使用了新的 operation类,并将其添加到了新的 operation队列中: 

#import <UIKit/UIKit.h>@class SimpleOperation;@interface Running_Tasks_Asynchronously_with_OperationsAppDelegate : UIResponder <UIApplicationDelegate>@property (nonatomic, strong) UIWindow *window;@property (nonatomic, strong) NSOperationQueue *operationQueue; @property (nonatomic, strong) SimpleOperation *firstOperation; @property (nonatomic, strong) SimpleOperation *secondOperation;@end

application delegate的实现部分如下: 

#import "Running_Tasks_Asynchronously_with_OperationsAppDelegate.h" #import "SimpleOperation.h"@implementation Running_Tasks_Asynchronously_with_OperationsAppDelegate @synthesize window = _window;@synthesize firstOperation;@synthesize secondOperation;@synthesize operationQueue;- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ NSNumber *firstNumber = [NSNumber numberWithInteger:111]; NSNumber *secondNumber = [NSNumber numberWithInteger:222]; self.firstOperation = [[SimpleOperation alloc]initWithObject:firstNumber];self.secondOperation = [[SimpleOperation alloc] initWithObject:secondNumber];self.operationQueue = [[NSOperationQueue alloc] init]; /* Add the operations to the queue */ [self.operationQueue addOperation:self.firstOperation]; [self.operationQueue addOperation:self.secondOperation]; NSLog(@"Main thread is here");self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible];return YES;}@end

打印到控制台窗口的结果与之前使用并发 invocation operation类似: 

Main thread is here
-[SimpleOperation main]
-[SimpleOperation main]
Parameter Object = 222
Parameter Object = 222
Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}Main Thread = <NSThread: 0x6810260>{name = (null), num = 1}Current Thread = <NSThread: 0x6a10b90>{name = (null), num = 3}Current Thread = <NSThread: 0x6a13f50>{name = (null), num = 4}