如果你想执行一系列的同步任务,你可以这么做
- (void) simpleOperationEntry:(id)paramObject{
NSLog(@"Parameter Object = %@", paramObject);
NSLog(@"Main Thread = %@", [NSThreadmainThread]);
NSLog(@"Current Thread = %@", [NSThreadcurrentThread]);
}
NSInvocationOperation *simpleOperation;
-(void)test6_12
{
NSNumber *simpleObject = [NSNumbernumberWithInteger:123];
simpleOperation = [[NSInvocationOperationalloc] initWithTarget:self
selector:@selector(simpleOperationEntry:)
object:simpleObject];
[simpleOperationstart];
}
输出:
2014-03-11 09:56:13.738 cookbook[478:a0b] Parameter Object = 123
2014-03-11 09:56:13.739 cookbook[478:a0b] Main Thread = <NSThread: 0x8920550>{name = (null), num = 1}
2014-03-11 09:56:13.739 cookbook[478:a0b] Current Thread = <NSThread: 0x8920550>{name = (null), num = 1}
就如NSInvocationOperation名字所表明的那样,其主要职责是调用一个对象内部的方法,也是使用operation最直接的方法。下一节将学到如何使得operation与调用线程异步执行。
接下来我们来看下block方式的:
-(void)test6_12_1
{
NSBlockOperation *simpleOperation;
simpleOperation = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"Main Thread = %@", [NSThreadmainThread]);
NSLog(@"Current Thread = %@", [NSThreadcurrentThread]);
NSUInteger counter = 0;
for (counter = 0; counter <1000;
counter++){
NSLog(@"Count = %lu", (unsignedlong)counter);
} }];
/* Start the operation */
[simpleOperationstart];
/* Print something out just to test if we have to wait
for the block to execute its code or not */
NSLog(@"Main thread is here");
}
输出:
2014-03-11 10:14:38.816 cookbook[530:a0b] Main Thread = <NSThread: 0x8961430>{name = (null), num = 1}
2014-03-11 10:14:38.817 cookbook[530:a0b] Current Thread = <NSThread: 0x8961430>{name = (null), num = 1}
2014-03-11 10:14:38.817 cookbook[530:a0b] Count = 0
2014-03-11 10:14:38.817 cookbook[530:a0b] Count = 1
。。。。。。。
2014-03-11 10:14:39.302 cookbook[530:a0b] Count = 997
2014-03-11 10:14:39.303 cookbook[530:a0b] Count = 998
2014-03-11 10:14:39.303 cookbook[530:a0b] Count = 999
2014-03-11 10:14:39.304 cookbook[530:a0b] Main thread is here
这说明,如果我们在主线程中启动了operation,它就会在主线程中执行。这当然是个不好的做法,繁重的事情不应该由主线程在干。
除了上面两个opération,我们也可以自己创建NSOperation的子类。在创建之前,我们必须明白几点
1,如果你不想用operation queue,你就应该在start方法里面detach子线程来执行。
如果你即不想用opération queue也不想你的opération异步执行,好吧,那你就直接在start里面调下main方法。
2,必须重写两个方法:isExecuting和isFinished,而且返回值必须是线程安全的。再通过kvo通知监听者状态的改变。
3,在main方法中实现自动释放池,因为你这个opération将来可能加到opération queue中。你应该确保你的opération可以在这两种方式下运行:手动start或opération queue start。
4,你应该设计一个初始化方法,所有别的初始化方法,包括默认的初始化方法都来调用你这个新的初始化方法。新的初始化方法应该是参数最多的,别人在调用它时能够传入正确的入参。
好,来个例子:
头文件
#import <Foundation/Foundation.h>
@interface CountingOperation :NSOperation
/* Designated Initializer */
- (id) initWithStartingCount:(NSUInteger)paramStartingCount
endingCount:(NSUInteger)paramEndingCount;
@end
.m文件
#import "CountingOperation.h"
@implementation CountingOperation
NSUInteger startingCount;
NSUInteger endingCount;
BOOL finished;
BOOL executing;
- (id) init {
return([selfinitWithStartingCount:0
endingCount:1000]);
}
- (id)initWithStartingCount:(NSUInteger)paramStartingCount
endingCount:(NSUInteger)paramEndingCount{
self = [super init];
if (self !=nil){
/* Keep these values for the main method */
startingCount = paramStartingCount; endingCount = paramEndingCount;
}
return(self);
}
- (void) start {
/* If we are cancelled before starting, then
we have to return immediately and generate the required KVO notifications */
if ([self isCancelled]){
/* If this operation *is* cancelled */
/* KVO compliance */
[selfwillChangeValueForKey:@"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 didChangeValueForKey:@"isExecuting"];
[self main];
}
}
- (void) main {
@try {
/* Here is the autorelease pool */
@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 exists
if the taskIsFinished variable is set to YES or the operation has been cancelled */
while (taskIsFinished == NO && [self isCancelled] == NO){
/* Perform the task here */
NSLog(@"Main Thread = %@", [NSThread mainThread]);
NSLog(@"Current Thread = %@", [NSThread currentThread]);
NSUInteger counter = startingCount;
for (counter = startingCount;
counter < endingCount;
counter++){
NSLog(@"Count = %lu", (unsignedlong)counter);
}
/* Very important. This way we can get out of the
loop and we are still complying with the cancellation rules of operations */
taskIsFinished = YES; }
/* KVO compliance. Generate the required KVO notifications */
[selfwillChangeValueForKey:@"isFinished"];
[selfwillChangeValueForKey:@"isExecuting"];
finished = YES;
executing =NO;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
}
}
@catch (NSException * e) {
NSLog(@"Exception %@", e);
}
}
- (BOOL) isFinished{
/* Simply return the value */
return(finished);
}
- (BOOL) isExecuting{
/* Simply return the value */
return(executing);
}
@end
调用方法
-(void)test6_12_2
{
CountingOperation *simpleOperation;
simpleOperation = [[CountingOperationalloc] initWithStartingCount:0endingCount:1000];
[simpleOperationstart];
NSLog(@"Main thread is here");
}
输出:
2014-03-11 11:29:29.248 cookbook[593:a0b] Main Thread = <NSThread: 0x8944950>{name = (null), num = 1}
2014-03-11 11:29:29.248 cookbook[593:a0b] Current Thread = <NSThread: 0x8944950>{name = (null), num = 1}
2014-03-11 11:29:29.248 cookbook[593:a0b] Count = 0
2014-03-11 11:29:29.249 cookbook[593:a0b] Count = 1
。。。。。。。。
2014-03-11 11:29:29.743 cookbook[593:a0b] Count = 996
2014-03-11 11:29:29.743 cookbook[593:a0b] Count = 997
2014-03-11 11:29:29.743 cookbook[593:a0b] Count = 998
2014-03-11 11:29:29.744 cookbook[593:a0b] Count = 999
2014-03-11 11:29:29.744 cookbook[593:a0b] Main thread is here