美文网首页
Operation Queues

Operation Queues

作者: 大美象 | 来源:发表于2017-02-19 20:32 被阅读16次

    Operation Queues 在GCD之前就有了,其中的某些设计原理因Operation Queues而流行,GCD就是基于这些原理构建的。从iOS4与Mac OSX 10.6开始,Operation Queues在底层就是用GCD来实现的。

    GCD是纯C的API,而Operation Queues是Objective-C的对象。

    NSOperation

    很多执行任务类型的案例都很好的运用了NSOperation
    ,包括网络请求,图像压缩,自然语言处理或者其他很多需要返回处理后数据的、可重复的、结构化的、相对长时间运行的任务
    比如我们经常使用的AFNetworking

    @interface AFURLConnectionOperation : NSOperation <NSURLConnectionDelegate, NSURLConnectionDataDelegate, NSSecureCoding, NSCopying>
    @property (nonatomic, strong) NSSet *runLoopModes;
    @property (readonly, nonatomic, strong) NSURLRequest *request;
    @property (readonly, nonatomic, strong) NSURLResponse *response;
    @property (readonly, nonatomic, strong) NSError *error;
    @property (readonly, nonatomic, strong) NSData *responseData;
    @property (readonly, nonatomic, copy) NSString *responseString;
    ...
    

    SDWebImage

    extern NSString *const SDWebImageDownloadStartNotification;
    extern NSString *const SDWebImageDownloadReceiveResponseNotification;
    extern NSString *const SDWebImageDownloadStopNotification;
    extern NSString *const SDWebImageDownloadFinishNotification;
    
    继承自NSOperation
    @interface SDWebImageDownloaderOperation : NSOperation <SDWebImageOperation>
    @property (strong, nonatomic, readonly) NSURLRequest *request;
    @property (assign, nonatomic) BOOL shouldDecompressImages;
    ...
    - (id)initWithRequest:(NSURLRequest *)request
                  options:(SDWebImageDownloaderOptions)options
                 progress:(SDWebImageDownloaderProgressBlock)progressBlock
                completed:(SDWebImageDownloaderCompletedBlock)completedBlock
                cancelled:(SDWebImageNoParamsBlock)cancelBlock;
    
    @end
    

    子类化NSOperation有两种类型

    • 非并发型NSOperation
      子类化一个非并发型operation非常简单,只需要重写main方法即可。其他的一些复杂的操作比如工程配置,KVO通知父类已经帮我们做好了。
      main方法执行结束,该类就被释放了。
    • 并发型NSOperation
      至少需要实现以下几个方法
    - (void)start;
    - (BOOL)isConcurrent;
    - (BOOL)isExecuting;
    - (BOOL)isFinished;
    

    以AFNetworking为例

    @implementation AFURLConnectionOperation
    - (instancetype)initWithRequest:(NSURLRequest *)urlRequest {
        NSParameterAssert(urlRequest);
    
        self = [super init];
        if (!self) {
            return nil;
        }
    
        _state = AFOperationReadyState;
    
        self.lock = [[NSRecursiveLock alloc] init];
        self.lock.name = kAFNetworkingLockName;
    
        self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes];
    
        self.request = urlRequest;
    
        self.shouldUseCredentialStorage = YES;
    
        self.securityPolicy = [AFSecurityPolicy defaultPolicy];
    
        return self;
    }
    - (void)start {
        [self.lock lock];
        if ([self isCancelled]) {
            [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
        } else if ([self isReady]) {
            self.state = AFOperationExecutingState;
    
            [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
        }
        [self.lock unlock];
    }
    
    - (BOOL)isConcurrent {
        return YES;
    }
    - (BOOL)isExecuting {
        return self.state == AFOperationExecutingState;
    }
    
    - (BOOL)isFinished {
        return self.state == AFOperationFinishedState;
    }
    
    

    发出isFinished的kvo通知,代表着opration结束

    typedef NS_ENUM(NSInteger,MyOperationState) {
        MyOperationStateReady,
        MyOperationStateExecuting,
        MyOperationStateFinished,
    };
    
    @interface MyOperation ()
    @property (nonatomic, copy) MyOperationAction action;
    @property (nonatomic, assign) MyOperationState state;
    @property (nonatomic, readonly,getter=isCancelled) BOOL cancel;
    @end
    
    @implementation MyOperation
    
    #pragma mark - Override
    - (BOOL)isReady{
        return self.state == MyOperationStateReady;
    }
    
    - (BOOL)isConcurrent{
        return YES;
    }
    
    - (BOOL)isExecuting{
        return self.state == MyOperationStateExecuting;
    }
    
    - (BOOL)isFinished{
        return self.state == MyOperationStateFinished;
    }
    
    - (void)cancel{
        [self willChangeValueForKey:@"isCancelled"];
        _cancel = YES;
        [self didChangeValueForKey:@"isCancelled"];
    }
    
    //在start中建立一个thread执行任务
    - (void)start{
        if([self isReady]){
            [self willChangeValueForKey:@"isExecuting"];
            [self willChangeValueForKey:@"isReady"];
            self.state = MyOperationStateExecuting;
            [self didChangeValueForKey:@"isReady"];
            [self didChangeValueForKey:@"isExecuting"];
            
            [self performSelector:@selector(operationDidStart) onThread:[[self class] threadForMyOperation] withObject:nil waitUntilDone:NO];
        }
    }
    
    - (void)operationDidStart{
        if (self.isCancelled) {
            [self willChangeValueForKey:@"isFinished"];
            [self willChangeValueForKey:@"isCancelled"];
            self.state = MyOperationStateFinished;
            [self didChangeValueForKey:@"isCancelled"];
            [self didChangeValueForKey:@"isFinished"];
        }else{
            self.action();
            [self willChangeValueForKey:@"isFinished"];
            [self willChangeValueForKey:@"isExecuting"];
            self.state = MyOperationStateFinished;
            [self didChangeValueForKey:@"isExecuting"];
            [self didChangeValueForKey:@"isFinished"];
        }
    }
    
    #pragma mark Create Singleton Thread
    + (void)keepThreadAlive{
        do{
            @autoreleasepool {
                [[NSRunLoop currentRunLoop] run];
            }
        }while (YES);
    }
    
    + (NSThread*)threadForMyOperation{
        static NSThread *_threadInstance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _threadInstance = [[NSThread alloc] initWithTarget:self selector:@selector(keepThreadAlive) object:nil];
            _threadInstance.name = @"MyOperation.Thread";
            [_threadInstance start];
        });
        
        return _threadInstance;
    }
    @end
    
    

    NSOPerationQueue

    但是仅仅把计算封装进一个对象而不做其他处理显然没有多大用处,我们还需要NSOperationQueue来大显身手。当operation被添加到队列之后,NSOperationQueue会浏览所有的operation,优先运行那些处于ready状态且优先级较高的操作。

    http://nshipster.cn/nsoperation/

    //创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];  
    
    //将NSOperation加入队列之后,queue会自动执行该operation
    [queue addOperation:operation];
    
    //设置并发数目为2
    queue.maxConcurrentOperationCount = 2;
    

    取消任务

    // 取消一个任务 
    [operation cancel];  
    
    // 取消queue中所有的任务  
    [queue cancelAllOperations];
    

    http://nshipster.cn/nsoperation/
    http://blog.leichunfeng.com/blog/2015/07/29/ios-concurrency-programming-operation-queues/
    refrence

    相关文章

      网友评论

          本文标题:Operation Queues

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