iOS多线程之NSOperation/NSOperationQueue

//
//  JSC_NSOperation.m
//  ios多线程学习
//
//  Created by huasu on 17/2/28.
//  Copyright © 2017年 JY. All rights reserved.
//

/*

 NSOperation/NSOperationQueue 面向对象的线程技术
 使用 NSOperation的方式有两种,
 一种是用定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。

 */


#import "JSC_NSOperation.h"

#define kURL @"http://s10.sinaimg.cn/mw690/56279263h7bdc5a0791f9&690.png"

@interface JSC_NSOperation ()
@property (nonatomic,weak)UIImageView *imageview;
@property (nonatomic,weak)UIImageView *imageview2;
@property (nonatomic,strong)NSMutableArray *array;
@end

@implementation JSC_NSOperation

-(NSMutableArray *)array
{
    if (_array==nil) {
        _array=[NSMutableArray array];
    }
    return _array;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //使用NSInvocationOperation
    //[self text1];

    //使用NSBlockOperation
    //text2主要是如何使用,以及两种执行线程的方法
//    [self text2];

    //text3主要讲依赖关系的使用,以及不同方式使用多线程方法
     [self text3];

}
-(void)text1
{
    UIImageView *imageview=[[UIImageView alloc]init];
    self.imageview=imageview;
    imageview.frame=CGRectMake(10, 100, 200, 200);
    [self.view addSubview:imageview];

    UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame=CGRectMake(50, 400, 220, 25);
    [button setTitle:@"加载图片" forState:UIControlStateNormal];
    //添加方法
    [button addTarget:self action:@selector(btnclick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}

-(void)btnclick
{

    //创建操作队列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    // 实例化队列操作
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self
                                                                           selector:@selector(downloadImage:)
                                                                             object:kURL];

    // 如果使用start,会在当前线程启动操作
    //  [op1 start];

    //  一旦将操作添加到操作队列,操作就会启动
    [queue addOperation:operation];

}
-(void)downloadImage:(NSString *)url{
    NSURL *nsUrl = [NSURL URLWithString:url];
    NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
    UIImage * image = [[UIImage alloc]initWithData:data];

    //下载完成后用performSelectorOnMainThread执行主线程updateUI方法。
    [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
-(void)updateUI:(UIImage*) image{
    self.imageview.image = image;
}









-(void)text2
{
    UIImageView *imageview=[[UIImageView alloc]init];
    self.imageview=imageview;
    imageview.frame=CGRectMake(10, 100, 200, 200);
    [self.view addSubview:imageview];

    UIImageView *imageview2=[[UIImageView alloc]init];
    self.imageview2=imageview2;
    imageview2.frame=CGRectMake(10, 400, 200, 200);
    [self.view addSubview:imageview2];

    UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame=CGRectMake(50, 400, 220, 25);
    [button setTitle:@"加载图片" forState:UIControlStateNormal];
    //添加方法
    [button addTarget:self action:@selector(btntouch) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];

}
-(void)btntouch
{
    //创建操作队列
    NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];

    //设置最大并发线程数
    operationQueue.maxConcurrentOperationCount=2;


    //方法1:创建操作块添加到队列
    //下载图片1
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
         NSLog(@"下载 %@" , [NSThread currentThread]);
        [self loadImage:1];


    }];


    //下载图片2
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载 %@" , [NSThread currentThread]);

        [self loadImage:2];


    }];

    //将操作添加到队列NSOperationQueue即可启动多线程执行
    [operationQueue addOperation:op1];
    [operationQueue addOperation:op2];


//    //方法2:接使用操队列添加操作
//    //下载图片1
//    [operationQueue addOperationWithBlock:^{
//        [self loadImage:1];
//    }];
//    //下载图片2
//    [operationQueue addOperationWithBlock:^{
//        [self loadImage:2];
//    }];

}

-(void)loadImage:(int)index{


    if (index==1) {
        NSURL *nsUrl = [NSURL URLWithString:kURL];
        NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
        //更新UI界面,此处调用了主线程队列的方法(mainQueue是UI主线程)
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self updateImageWithData:data andIndex:index];
        }];

    }else
    {
        NSURL *nsUrl = [NSURL URLWithString:kURL];
        NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
        //更新UI界面,此处调用了主线程队列的方法(mainQueue是UI主线程)
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self updateImageWithData:data andIndex:index];
        }];
    }
}
-(void)updateImageWithData:(NSData *)data andIndex:(int )index{

     UIImage *image=[UIImage imageWithData:data];
    if (index==1) {
        self.imageview.image=image;
    }else{
        self.imageview2.image=image;
    }

}





-(void)text3
{
    UIImageView *imageview=[[UIImageView alloc]init];
    self.imageview=imageview;
    imageview.frame=CGRectMake(10, 100, 200, 200);
    [self.view addSubview:imageview];

    UIImageView *imageview2=[[UIImageView alloc]init];
    self.imageview2=imageview2;
    imageview2.frame=CGRectMake(10, 400, 200, 200);
    [self.view addSubview:imageview2];

    UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame=CGRectMake(50, 400, 220, 25);
    [button setTitle:@"加载图片" forState:UIControlStateNormal];
    //添加方法
    [button addTarget:self action:@selector(btntext) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];


}
-(void)btntext
{
    //创建操作队列
    NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];

    //设置最大并发线程数
    operationQueue.maxConcurrentOperationCount=2;

    //下载图片1
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载 %@" , [NSThread currentThread]);

        NSURL *nsUrl = [NSURL URLWithString:kURL];
        NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
        UIImage *image=[UIImage imageWithData:data];
        [self.array addObject:image];

    }];


    //下载图片2
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载 %@" , [NSThread currentThread]);

        NSURL *nsUrl = [NSURL URLWithString:kURL];
        NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
        UIImage *image=[UIImage imageWithData:data];
        [self.array addObject:image];

    }];

    // 显示
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"更新UI %@" , [NSThread currentThread]);

        self.imageview.image=self.array[0];
        self.imageview2.image=self.array[1];

    }];


    // 添加操作之间的依赖关系,所谓“依赖”关系,就是等待前一个任务完成后,后一个任务才能启动
    // 依赖关系可以跨线程队列实现
    // 提示:在指定依赖关系时,注意不要循环依赖,否则不工作。
    //依赖补充:假如我们有很多张图片,需要先加载firstBlockOperation线程中处理的图片 如何做呢.请看下面/*注释中的代码
    /*
     NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];

     operationQueue.maxConcurrentOperationCount=5;

     NSBlockOperation *firstBlockOperation=[NSBlockOperation blockOperationWithBlock:^{
     NSURL *nsUrl = [NSURL URLWithString:kURL];
     NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
     //更新UI界面,此处调用了主线程队列的方法(mainQueue是UI主线程)
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{
     self.imageview.image=image;
     }];
     }];
     //假如还需要加载五张图片
     for (int i=0; i<5; ++i) {
     NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{

     NSURL *nsUrl = [NSURL URLWithString:kURL];
     NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
     //更新UI界面,此处调用了主线程队列的方法(mainQueue是UI主线程)
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{
     //不想再多写demo了 所以我们假设这五张图片的加载就是更换imageview2的image吧
     self.imageview2.image=image;
     }];
     }];
     //设置依赖操作为第一张图片加载操作,这里我们可以看到,依赖关系不仅可以 a依赖b b依赖c 也可以a依赖c  b依赖c这样
     [blockOperation addDependency:firstBlockOperation];

     [operationQueue addOperation:blockOperation];

     }
     //将第一个图片的加载操作加入线程队列
     [operationQueue addOperation:lastBlockOperation];
     //逻辑分析:以上代码我们创建了一个队列,然后首先开启了firstBlockOperation这个线程,但是我们并没有将它加入队列,所以程序继续往下执行,走for循环,然后分别创建了五个线程加载图片,每创建一个线程我们都会设置与firstBlockOperation的依赖关系,然后加入队列,但是由于依赖关系的存在,就算加入了每一个线程加入了队列,可是firstBlockOperation并没有在队列中,依赖关系让这五个线程依然不能执行,直到for循环结束,我们执行[operationQueue addOperation:lastBlockOperation]时,这时候firstBlockOperation线程才加入队列,那么此时就会先走这个线程,将图片加载出来,然后才会走另外的五个线程。这时候加载顺序时,先加载imageview,然后其余五个线程则是无序的。

     */
    [op2 addDependency:op1];
    [op3 addDependency:op2];

    [operationQueue addOperation:op1];
    [operationQueue addOperation:op2];

    //更新UI使用主线程队列 有两种方式
    //第一种
    [[NSOperationQueue mainQueue] addOperation:op3];

    //第二种,我们可以在Block里面直接写更新ui的方法,只是如果这样,我们这个text3就没发添加op3的依赖关系了,所以暂时不用这种
    //    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    //
    //
    //    }];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值