zoukankan      html  css  js  c++  java
  • IOS多线程之NSOperation

    我们可以使用NSOperation和NSOperationQueue实现多线程开发,NSOperationQueue的概念类似线程池,相比较NSThread,NSOperation提供了面向对象的语法。

    使用NSOperation的过程是创建一个operation

    NSOperation通常不会直接拿来使用,我们使用它的子类NSInvocationOperation或者NSBlockOperation,又或者自定义NSOperation的子类,下面分别介绍这三种方式。

    NSInvocationOperation

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(threadOperation) object:nil];
        //如果直接使用start,operation会马上运行在主线程,我们基本不会这样使用
        //[operation start];
        
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        //将operation加入到operationqueue后,operationqueue会自动执行start方法,且运行在多线程中
        [queue addOperation:operation];
    }

    关于NSOperationQueue我们还可以设置它的相关属性

    queue.maxConcurrentOperationCount  获取或者设置最大的并发运行数,默认值为-1,表示不限制同时运行的线程数

    queue.name  设置线程池名称

    [NSOperationQueue currentQueue]  获取当前线程池

    [NSOperationQueue mainQueue]  获取主线程池

    [queue cancelAllOperations]  对线程池中的线程执行cancel方法设置取消标记,

     

    NSBlockOperation

    NSBlockOpration的使用流程基本与NSInvocationOperation一致,只是使用了block代替selector

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        
        _imageview = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 100, 80)];
        [self.view addSubview:_imageview];
        
        
        NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            
            NSLog(@"%hhd",[NSThread isMainThread]);
            NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.iyi8.com/uploadfile/2014/1002/20141002112243630.jpg"]];
            
            
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                NSLog(@"%hhd",[NSThread isMainThread]);
                [_imageview setImage:[UIImage imageWithData:data]];
            }];
        }];
        
        //为operation添加执行完毕的block
        operation.completionBlock = ^{
            NSLog(@"operation done");
        };
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        [queue addOperation:operation];
    }

    上面代码在多线程中网络请求图片,并在主线程中对ui进行更新,NSBlockOperation比NSInvocationOperation更加方便常用

    自定义NSOperation子类

    上面我们直接使用了框架中提供的NSOperation子类,我们还可以自己定义NSoperation子类

    自定义Operation的步骤如下

    1 继承NSOperation

    2 实现main函数

    3 在main函数中创建自动释放池

    4 把任务代码写在自动释放池中

    下面我们自定义一个NSOperation子类,用来下载图片

    ZLTOperation.h
    #import <Foundation/Foundation.h>
    
    @protocol DownImageProtocal;
    
    @interface ZLTOperation : NSOperation
    -(id)initWithImageUrl:(NSURL *)url delagete:(id<DownImageProtocal>) delegate;
    @end
    
    @protocol DownImageProtocal <NSObject>
    
    -(void)updateViewWithImage:(UIImage *)image;
    
    @end
    
    ZLTOperation.m
    #import "ZLTOperation.h"
    @interface ZLTOperation() {
        NSURL *_imageUrl;
        id<DownImageProtocal> _delegate;
    }
    @end
    
    @implementation ZLTOperation
    -(id)initWithImageUrl:(NSURL *)url delagete:(id<DownImageProtocal>) delegate {
        self = [super init];
        if (self) {
            _imageUrl = url;
            _delegate = delegate;
        }
        return self;
    }
    
    - (void)main {
        @autoreleasepool {
            //任务是否被取消
            if ([self isCancelled]) {
                return;
            }
            
            NSData *data = [NSData dataWithContentsOfURL:_imageUrl];
            
            //任务是否被取消
            if ([self isCancelled]) {
                return;
            }
            
            if ([_delegate respondsToSelector:@selector(updateViewWithImage:)]) {
                [(NSObject *)_delegate performSelectorOnMainThread:@selector(updateViewWithImage:) withObject:[UIImage imageWithData:data] waitUntilDone:NO];
            }
        }
    }
    @end

    测试

    ZViewController.h
    @interface ZViewController : UIViewController<DownImageProtocal>
    
    @end
    
    ZViewController.m
    @interface ZViewController () {
        UIImageView *_imageview;
    }
    
    @end
    
    @implementation ZViewController
    
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            // Custom initialization
        }
        return self;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        
        _imageview = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 100, 80)];
        [self.view addSubview:_imageview];
        
        ZLTOperation *operation = [[ZLTOperation alloc] initWithImageUrl:[NSURL URLWithString:@"http://www.iyi8.com/uploadfile/2014/1002/20141002112243630.jpg"] delagete:self];
        
        
        //为operation添加执行完毕的block
        operation.completionBlock = ^{
            NSLog(@"operation done");
        };
        
        
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        [queue addOperation:operation];
    }
    
    - (void)updateViewWithImage:(UIImage *)image {
        _imageview.image = image;
    }
    @end

    NSOperation其他常用方法和属性

    - (BOOL)isCancelled;

    - (void)cancel;  取消任务

      

    - (void)setCompletionBlock:(void (^)(void))block  添加任务完成block

     

    - (double)threadPriority

    - (void)setThreadPriority:(double)p   任务优先级

     

    - (void)addDependency:(NSOperation *)op;

    - (void)removeDependency:(NSOperation *)op;

    - (NSArray *)dependencies;  添加依赖

    依赖用来控制线程执行顺序,如果A添加B为他的依赖,那么只有当操作B完成后才会执行操作A,操作依赖关系可以设置多个,例如A依赖于B、B依赖于C…但是千万不要设置为循环依赖关系(例如A依赖于B,B依赖于C,C又依赖于A),否则是不会被执行的。

     

    并发的NSOperation

    前面提过直接执行operation的start方法时,operation会运行在主线程,这是因为NSOperation默认是非并发的,我们也可以自己实现并发的operation类,这需要重载一系列方法,创建并发operation的一般步骤如下

    1. 你需要创建一个subclass
    2. 除了重载main方法,实现并发你还需要至少重载start,isConcurrent,isExecuting,isFinished四个方法
    3. start里,创建Thread或者调用一个异步函数
    4. 更新isExecuting,并且发送相应KVO消息
    5. 任务结束后,你还得更新isExecuting 和 isFinished,发送相应KVO消息

    一般我们不需要创建并发的NSOperation,配合NSOperationQueue来调用,而不是自己调用start

  • 相关阅读:
    在IT行业工作如何获得高薪?选择前沿的技术,把准方向,有技术有人缘
    如何去做不想做的事情的 - 10个建议
    如何去做不想做的事情的 - 10个建议
    项目管理
    项目管理
    Spring Quartz 定时任务
    Spring Quartz 定时任务
    Spring @Transactional (一)
    Spring @Transactional (一)
    Search Insert Position
  • 原文地址:https://www.cnblogs.com/zanglitao/p/4064449.html
Copyright © 2011-2022 走看看