//
// 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
iOS多线程之NSOperation/NSOperationQueue
最新推荐文章于 2024-05-18 20:38:52 发布