zoukankan      html  css  js  c++  java
  • NSOperation简单介绍/NSOperation基本操作/自定义NSOperation

    NSOperation简单介绍

    一、NSOperation简介

    1.简单说明

    NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程

    NSOperation和NSOperationQueue实现多线程的具体步骤:

    (1)先将需要执行的操作封装到一个NSOperation对象中

    (2)然后将NSOperation对象添加到NSOperationQueue中

    (3)系统会⾃动将NSOperationQueue中的NSOperation取出来

    (4)将取出的NSOperation封装的操作放到⼀条新线程中执⾏

     2.NSOperation的子类

    NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类

    使用NSOperation⼦类的方式有3种:

    (1)NSInvocationOperation

    (2)NSBlockOperation

    (3)自定义子类继承NSOperation,实现内部相应的⽅法

    二、 具体说明

    1.NSInvocationOperation子类

    创建对象和执行操作:

    复制代码
    1  //创建操作对象,封装要执行的任务
    2     //NSInvocationOperation   封装操作
    3     NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
    4     
    5     //执行操作
    6     [operation start];
    复制代码

    说明:一旦执⾏操作,就会调用target的test方法

    代码示例:

    复制代码
     9 #import "YYViewController.h"
    10 
    11 @interface YYViewController ()
    12 
    13 @end
    14 
    15 @implementation YYViewController
    16 
    17 - (void)viewDidLoad
    18 {
    19     [super viewDidLoad];
    20     
    21     //NSOperation:抽象类,不具备封装功能
    22     
    23     //创建操作对象,封装要执行的任务
    24     //NSInvocationOperation   封装操作
    25     NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
    26     
    27     //执行操作
    28     [operation start];
    29 
    30 }
    31 
    32 -(void)test
    33 {
    34     
    35     NSLog(@"--test--%@--",[NSThread currentThread]);
    36 }
    37 @end
    复制代码

    打印查看:

    注意:操作对象默认在主线程中执行,只有添加到队列中才会开启新的线程。即默认情况下,如果操作没有放到队列中queue中,都是同步执行。只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作 

    2.NSBlockOperation子类

    创建对象和添加操作:

    复制代码
     1   //创建NSBlockOperation操作对象
     2     NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
     3         //......
     4     }];
     5     
     6     //添加操作
     7     [operation addExecutionBlock:^{
     8         //....
     9     }];
    10     
    复制代码

    代码示例:

    代码1:

    复制代码
     9 #import "YYViewController.h"
    10 
    11 @interface YYViewController ()
    12 
    13 @end
    14 
    15 @implementation YYViewController
    16 
    17 - (void)viewDidLoad
    18 {
    19     [super viewDidLoad];
    20     
    21     //创建NSBlockOperation操作对象
    22     NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
    23         NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
    24     }];
    25     
    26     
    27     //开启执行操作
    28     [operation start];
    29 }
    30 @end
    复制代码

    打印查看:

    代码2:

    复制代码
     9 #import "YYViewController.h"
    10 
    11 @interface YYViewController ()
    12 
    13 @end
    14 
    15 @implementation YYViewController
    16 
    17 - (void)viewDidLoad
    18 {
    19     [super viewDidLoad];
    20     
    21     //创建NSBlockOperation操作对象
    22     NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
    23         NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
    24     }];
    25     
    26     //添加操作
    27     [operation addExecutionBlock:^{
    28         NSLog(@"NSBlockOperation1------%@",[NSThread currentThread]);
    29     }];
    30     
    31     [operation addExecutionBlock:^{
    32         NSLog(@"NSBlockOperation2------%@",[NSThread currentThread]);
    33     }];
    34     
    35     //开启执行操作
    36     [operation start];
    37 }
    38 @end
    复制代码

    注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作 

    3.NSOperationQueue

    NSOperationQueue的作⽤:NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执行的

    如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作

    添加操作到NSOperationQueue中,自动执行操作,自动开启线程

    复制代码
     1     //创建NSOperationQueue
     2     NSOperationQueue * queue=[[NSOperationQueue alloc]init];
     3     //把操作添加到队列中
     4     //第一种方式
     5     [queue addOperation:operation1];
     6     [queue addOperation:operation2];
     7     [queue addOperation:operation3];
     8     //第二种方式
     9     [queue addOperationWithBlock:^{
    10         NSLog(@"NSBlockOperation3--4----%@",[NSThread currentThread]);
    11     }];
    复制代码

    - (void)addOperation:(NSOperation *)op;
    - (void)addOperationWithBlock:(void (^)(void))block; 

    代码示例:

    复制代码
     9 #import "YYViewController.h"
    10 
    11 @interface YYViewController ()
    12 
    13 @end
    14 
    15 @implementation YYViewController
    16 
    17 - (void)viewDidLoad
    18 {
    19     [super viewDidLoad];
    20 
    21     //创建NSInvocationOperation对象,封装操作
    22     NSInvocationOperation *operation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test1) object:nil];
    23     NSInvocationOperation *operation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test2) object:nil];
    24     //创建对象,封装操作
    25     NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{
    26         NSLog(@"NSBlockOperation3--1----%@",[NSThread currentThread]);
    27     }];
    28     [operation3 addExecutionBlock:^{
    29         NSLog(@"NSBlockOperation3--2----%@",[NSThread currentThread]);
    30     }];
    31     
    32     //创建NSOperationQueue
    33     NSOperationQueue * queue=[[NSOperationQueue alloc]init];
    34     //把操作添加到队列中
    35     [queue addOperation:operation1];
    36     [queue addOperation:operation2];
    37     [queue addOperation:operation3];
    38 }
    39 
    40 -(void)test1
    41 {
    42     NSLog(@"NSInvocationOperation--test1--%@",[NSThread currentThread]);
    43 }
    44 
    45 -(void)test2
    46 {
    47     NSLog(@"NSInvocationOperation--test2--%@",[NSThread currentThread]);
    48 }
    49 
    50 @end
    复制代码

    打印效果:

    注意:系统自动将NSOperationqueue中的NSOperation对象取出,将其封装的操作放到一条新的线程中执行。上面的代码示例中,一共有四个任务,operation1和operation2分别有一个任务,operation3有两个任务。一共四个任务,开启了四条线程。通过任务执行的时间全部都是273可以看出,这些任务是并行执行的。

    提示:队列的取出是有顺序的,与打印结果并不矛盾。这就好比,选手A,BC虽然起跑的顺序是先A,后B,然后C,但是到达终点的顺序却不一定是A,B在前,C在后。

    下面使用for循环打印,可以更明显的看出任务是并发执行的。

    代码示例:

    复制代码
     1 #import "YYViewController.h"
     2 
     3 @interface YYViewController ()
     4 
     5 @end
     6 
     7 @implementation YYViewController
     8 
     9 - (void)viewDidLoad
    10 {
    11     [super viewDidLoad];
    12 
    13     //创建NSInvocationOperation对象,封装操作
    14     NSInvocationOperation *operation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test1) object:nil];
    15     NSInvocationOperation *operation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test2) object:nil];
    16     //创建对象,封装操作
    17     NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{
    18         for (int i=0; i<5; i++) {
    19             NSLog(@"NSBlockOperation3--1----%@",[NSThread currentThread]);
    20         }
    21     }];
    22     [operation3 addExecutionBlock:^{
    23         for (int i=0; i<5; i++) {
    24         NSLog(@"NSBlockOperation3--2----%@",[NSThread currentThread]);
    25         }
    26     }];
    27     
    28     //创建NSOperationQueue
    29     NSOperationQueue * queue=[[NSOperationQueue alloc]init];
    30     //把操作添加到队列中
    31     [queue addOperation:operation1];
    32     [queue addOperation:operation2];
    33     [queue addOperation:operation3];
    34 }
    35 
    36 -(void)test1
    37 {
    38     for (int i=0; i<5; i++) {
    39     NSLog(@"NSInvocationOperation--test1--%@",[NSThread currentThread]);
    40     }
    41 }
    42 
    43 -(void)test2
    44 {
    45     for (int i=0; i<5; i++) {
    46     NSLog(@"NSInvocationOperation--test2--%@",[NSThread currentThread]);
    47     }
    48 }
    49 
    50 @end
    复制代码

    NSOperation基本操作

    一、并发数
    (1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3
    (2)最大并发数:同一时间最多只能执行的任务的个数。
    (3)最⼤大并发数的相关⽅方法
    - (NSInteger)maxConcurrentOperationCount;
    - (void)setMaxConcurrentOperationCount:(NSInteger)cnt; 
    说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能内存多久开多一点,内存少就开少一点。
    注意:num的值并不代表线程的个数,仅仅代表线程的ID。
    提示:最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。
     
    二、队列的取消,暂停和恢复

     (1)取消队列的所有操作

     - (void)cancelAllOperations;

    提⽰:也可以调用NSOperation的- (void)cancel⽅法取消单个操作

     (2)暂停和恢复队列

    - (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列

    - (BOOL)isSuspended; //当前状态

    (3)暂停和恢复的适用场合:在tableview界面,开线程下载远程的网络界面,对UI会有影响,使用户体验变差。那么这种情况,就可以设置在用户操作UI(如滚动屏幕)的时候,暂停队列(不是取消队列),停止滚动的时候,恢复队列。
     
    三、操作优先级

     (1)设置NSOperation在queue中的优先级,可以改变操作的执⾏优先级

    - (NSOperationQueuePriority)queuePriority;
    - (void)setQueuePriority:(NSOperationQueuePriority)p;

     (2)优先级的取值

    NSOperationQueuePriorityVeryLow = -8L,

    NSOperationQueuePriorityLow = -4L,

    NSOperationQueuePriorityNormal = 0,

    NSOperationQueuePriorityHigh = 4,

    NSOperationQueuePriorityVeryHigh = 8 

    说明:优先级高的任务,调用的几率会更大。

    四、操作依赖

    (1)NSOperation之间可以设置依赖来保证执行顺序,⽐如一定要让操作A执行完后,才能执行操作B,可以像下面这么写

    [operationB addDependency:operationA]; // 操作B依赖于操作

    (2)可以在不同queue的NSOperation之间创建依赖关系 

    注意:不能循环依赖(不能A依赖于B,B又依赖于A)。

    (3)代码示例

    复制代码
     1 #import "YYViewController.h"
     2 
     3 @interface YYViewController ()
     4 
     5 @end
     6 
     7 @implementation YYViewController
     8 
     9 - (void)viewDidLoad
    10 {
    11     [super viewDidLoad];
    12 
    13     //创建NSInvocationOperation对象,封装操作
    14     NSInvocationOperation *operation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test1) object:nil];
    15     NSInvocationOperation *operation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test2) object:nil];
    16     //创建对象,封装操作
    17     NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{
    18         for (int i=0; i<5; i++) {
    19             NSLog(@"NSBlockOperation3--1----%@",[NSThread currentThread]);
    20         }
    21     }];
    22     [operation3 addExecutionBlock:^{
    23         for (int i=0; i<5; i++) {
    24         NSLog(@"NSBlockOperation3--2----%@",[NSThread currentThread]);
    25         }
    26     }];
    27     
    28     //设置操作依赖
    29     //先执行operation2,再执行operation1,最后执行operation3
    30     [operation3 addDependency:operation1];
    31     [operation1 addDependency:operation2];
    32     
    33     //不能是相互依赖
    34 //    [operation3 addDependency:operation1];
    35 //    [operation1 addDependency:operation3];
    36     
    37     //创建NSOperationQueue
    38     NSOperationQueue * queue=[[NSOperationQueue alloc]init];
    39     //把操作添加到队列中
    40     [queue addOperation:operation1];
    41     [queue addOperation:operation2];
    42     [queue addOperation:operation3];
    43 }
    44 
    45 -(void)test1
    46 {
    47     for (int i=0; i<5; i++) {
    48     NSLog(@"NSInvocationOperation--test1--%@",[NSThread currentThread]);
    49     }
    50 }
    51 
    52 -(void)test2
    53 {
    54     for (int i=0; i<5; i++) {
    55     NSLog(@"NSInvocationOperation--test2--%@",[NSThread currentThread]);
    56     }
    57 }
    58 
    59 @end
    复制代码
     
    打印查看:
    A做完再做B,B做完才做C。
    注意:一定要在添加之前,进行设置。
    提示:任务添加的顺序并不能够决定执行顺序,执行的顺序取决于依赖。使用Operation的目的就是为了让开发人员不再关心线程。
     
     
    5.操作的监听

    可以监听一个操作的执行完毕

    - (void (^)(void))completionBlock;
    - (void)setCompletionBlock:(void (^)(void))block; 

    代码示例

    第一种方式:可以直接跟在任务后面编写需要完成的操作,如这里在下载图片后,紧跟着下载第二张图片。但是这种写法有的时候把两个不相关的操作写到了一个代码块中,代码的可阅读性不强。

    复制代码
     1 #import "YYViewController.h"
     2 
     3 @interface YYViewController ()
     4 
     5 @end
     6 
     7 @implementation YYViewController
     8 
     9 - (void)viewDidLoad
    10 {
    11     [super viewDidLoad];
    12 
    13     //创建对象,封装操作
    14     NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
    15         NSLog(@"-operation-下载图片-%@",[NSThread currentThread]);
    16         //.....下载图片后继续进行的操作
    17         NSLog(@"--接着下载第二张图片--");
    18     }];
    19     
    20     //创建队列
    21     NSOperationQueue *queue=[[NSOperationQueue alloc]init];
    22     //把任务添加到队列中(自动执行,自动开线程)
    23     [queue addOperation:operation];
    24 }
    25 
    26 @end
    复制代码

    第二种方式:

    复制代码
     1 #import "YYViewController.h"
     2 
     3 @interface YYViewController ()
     4 
     5 @end
     6 
     7 @implementation YYViewController
     8 
     9 - (void)viewDidLoad
    10 {
    11     [super viewDidLoad];
    12 
    13     //创建对象,封装操作
    14     NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
    15         for (int i=0; i<10; i++) {
    16             NSLog(@"-operation-下载图片-%@",[NSThread currentThread]);
    17         }
    18     }];
    19     
    20     //监听操作的执行完毕
    21     operation.completionBlock=^{
    22         //.....下载图片后继续进行的操作
    23         NSLog(@"--接着下载第二张图片--");
    24     };
    25     
    26     //创建队列
    27     NSOperationQueue *queue=[[NSOperationQueue alloc]init];
    28     //把任务添加到队列中(自动执行,自动开线程)
    29     [queue addOperation:operation];
    30 }
    31 
    32 @end
    复制代码

    打印查看:

    说明:在上一个任务执行完后,会执行operation.completionBlock=^{}代码段,且是在当前线程执行(2)。

    自定义NSOperation

    一、实现一个简单的tableView显示效果

    实现效果展示:

    代码示例(使用以前在主控制器中进行业务处理的方式)

    1.新建一个项目,让控制器继承自UITableViewController。

    复制代码
     1 //
     2 //  YYViewController.h
     3 //  01-自定义Operation
     4 //
     5 //  Created by apple on 15-7-29.
     6 //  Copyright (c) 2015年 itcase. All rights reserved.
     7 //
     8 
     9 #import <UIKit/UIKit.h>
    10 
    11 @interface YYViewController : UITableViewController
    12 
    13 @end
    复制代码

    2.处理storyboard中得界面,如下:

    3.根据plist文件,字典转模型

    新建一个类,继承自NSObject,作为数据的模型

    YYappModel.h文件

    复制代码
     1 //
     2 //  YYappModel.h
     3 //  01-自定义Operation
     4 //
     5 //  Created by apple on 14-7-29.
     6 //  Copyright (c) 2015年 itcase. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 
    11 @interface YYappModel : NSObject
    12 /**
    13  *应用名称
    14  */
    15 @property(nonatomic,copy)NSString *name;
    16 /**
    17  *  应用图片
    18  */
    19 @property(nonatomic,copy)NSString *icon;
    20 /**
    21  *  应用的下载量
    22  */
    23 @property(nonatomic,copy)NSString *download;
    24 
    25 +(instancetype)appModelWithDict:(NSDictionary *)dict;
    26 -(instancetype)initWithDict:(NSDictionary *)dict;
    27 @end
    复制代码

    YYappModel.m文件

    复制代码
     1 //
     2 //  YYappModel.m
     3 //  01-自定义Operation
     4 //
     5 //  Created by apple on 15-7-29.
     6 //  Copyright (c) 2015年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYappModel.h"
    10 
    11 @implementation YYappModel
    12 
    13 -(instancetype)initWithDict:(NSDictionary *)dict
    14 {
    15     if (self=[super init]) {
    16         [self setValuesForKeysWithDictionary:dict];
    17     }
    18     return self;
    19 }
    20 
    21 //工厂方法
    22 +(instancetype)appModelWithDict:(NSDictionary *)dict
    23 {
    24     return [[self alloc]initWithDict:dict];
    25 }
    26 @end
    复制代码

    主控制器中得逻辑控制部分,YYViewController.m文件

    复制代码
     1 //
     2 //  YYViewController.m
     3 //  01-自定义Operation
     4 //
     5 //  Created by apple on 14-7-29.
     6 //  Copyright (c) 2015年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYViewController.h"
    10 #import "YYappModel.h"
    11 
    12 @interface YYViewController ()
    13 @property(nonatomic,strong)NSArray *apps;
    14 
    15 @end
    16 
    17 @implementation YYViewController
    18 #pragma mark- 懒加载
    19 -(NSArray *)apps
    20 {
    21     if (_apps==nil) {
    22         NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
    23         NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
    24         
    25         //字典转模型
    26         NSMutableArray *array=[NSMutableArray array];
    27         for (NSDictionary *dict in tempArray) {
    28             YYappModel *app=[YYappModel appModelWithDict:dict];
    29             [array addObject:app];
    30         }
    31         _apps=array;
    32     }
    33     return _apps;
    34 }
    35 
    36 #pragma mark-数据源方法
    37 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    38 {
    39     return self.apps.count;
    40 }
    41 
    42 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    43 {
    44     static NSString *ID=@"ID";
    45     UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
    46     if (cell==nil) {
    47         cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    48     }
    49     YYappModel *app=self.apps[indexPath.row];
    50     cell.textLabel.text=app.name;
    51     cell.detailTextLabel.text=app.download;
    52     
    53     //下载图片数据
    54     NSLog(@"加载图片数据---%@", [NSThread currentThread]);
    55     NSURL *url=[NSURL URLWithString:app.icon];
    56     NSData *data=[NSData dataWithContentsOfURL:url];
    57     UIImage *imgae=[UIImage imageWithData:data];
    58     cell.imageView.image=imgae;
    59     NSLog(@"完成显示");
    60     return cell;
    61 }
    62 
    63 @end
    复制代码

    打印查看:

    二、自定义NSOperation

    说明:上面的下载图片数据部分是一个非常耗时的操作,这个操作任务在主线程完成,会严重的影响到用户体验,造成UI卡的现象。下面通过自定义NSOperation,新开线程,让加载图片的任务异步执行。

    1.通过代理

    在上面的基础上,新建一个类,让其继承自NSOperation。

    YYdownLoadOperation.h文件

    复制代码
     1 //
     2 //  YYdownLoadOperation.h
     3 //  01-自定义Operation
     4 //
     5 //  Created by apple on 15-7-29.
     6 //  Copyright (c) 2015年 itcase. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 
    11 #pragma mark-设置代理和代理方法
    12 @class YYdownLoadOperation;
    13 @protocol YYdownLoadOperationDelegate <NSObject>
    14 -(void)downLoadOperation:(YYdownLoadOperation*)operation didFishedDownLoad:(UIImage *)image;
    15 @end
    16 
    17 @interface YYdownLoadOperation : NSOperation
    18 @property(nonatomic,copy)NSString *url;
    19 @property(nonatomic,strong)NSIndexPath *indexPath;
    20 @property(nonatomic,strong)id <YYdownLoadOperationDelegate> delegate;
    21 @end
    复制代码

    YYdownLoadOperation.m文件

    复制代码
     1 //
     2 //  YYdownLoadOperation.m
     3 //  01-自定义Operation
     4 //
     5 //  Created by apple on 14-6-26.
     6 //  Copyright (c) 2014年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYdownLoadOperation.h"
    10 
    11 @implementation YYdownLoadOperation
    12 -(void)main
    13 {
    14     NSURL *url=[NSURL URLWithString:self.url];
    15     NSData *data=[NSData dataWithContentsOfURL:url];
    16     UIImage *imgae=[UIImage imageWithData:data];
    17     
    18     NSLog(@"--%@--",[NSThread currentThread]);
    19     //图片下载完毕后,通知代理
    20     if ([self.delegate respondsToSelector:@selector(downLoadOperation:didFishedDownLoad:)]) {
    21         dispatch_async(dispatch_get_main_queue(), ^{//回到主线程,传递数据给代理对象
    22              [self.delegate downLoadOperation:self didFishedDownLoad:imgae];
    23         });
    24     }
    25 }
    26 @end
    复制代码

    主控制器中的业务逻辑:

    复制代码
     1 //
     2 //  YYViewController.m
     3 //  01-自定义Operation
     4 //
     5 //  Created by apple on 15-7-29.
     6 //  Copyright (c) 2015年 itcase. All rights reserved.
     7 //
     8 
     9 #import "YYViewController.h"
    10 #import "YYappModel.h"
    11 #import "YYdownLoadOperation.h"
    12 
    13 @interface YYViewController ()<YYdownLoadOperationDelegate>
    14 @property(nonatomic,strong)NSArray *apps;
    15 @property(nonatomic,strong)NSOperationQueue *queue;
    16 
    17 @end
    18 
    19 @implementation YYViewController
    20 #pragma mark- 懒加载apps
    21 -(NSArray *)apps
    22 {
    23     if (_apps==nil) {
    24         NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
    25         NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
    26         
    27         //字典转模型
    28         NSMutableArray *array=[NSMutableArray array];
    29         for (NSDictionary *dict in tempArray) {
    30             YYappModel *app=[YYappModel appModelWithDict:dict];
    31             [array addObject:app];
    32         }
    33         _apps=array;
    34     }
    35     return _apps;
    36 }
    37 
    38 #pragma mark-懒加载queue
    39 -(NSOperationQueue *)queue
    40 {
    41     if (_queue==Nil) {
    42         _queue=[[NSOperationQueue alloc]init];
    43         //设置最大并发数为3
    44         _queue.maxConcurrentOperationCount=3;
    45     }
    46     return _queue;
    47 }
    48 
    49 #pragma mark-数据源方法
    50 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    51 {
    52     return self.apps.count;
    53 }
    54 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    55 {
    56     static NSString *ID=@"ID";
    57     UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
    58     if (cell==nil) {
    59         cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    60     }
    61     YYappModel *app=self.apps[indexPath.row];
    62     cell.textLabel.text=app.name;
    63     cell.detailTextLabel.text=app.download;
    64     
    65     //下载图片数据
    66 //    NSLog(@"加载图片数据---%@", [NSThread currentThread]);
    67 //    NSURL *url=[NSURL URLWithString:app.icon];
    68 //    NSData *data=[NSData dataWithContentsOfURL:url];
    69 //    UIImage *imgae=[UIImage imageWithData:data];
    70 //    cell.imageView.image=imgae;
    71     
    72     //创建一个OPeration对象
    73     YYdownLoadOperation *operation=[[YYdownLoadOperation alloc]init];
    74     operation.url=app.icon;
    75     operation.indexPath=indexPath;
    76     operation.delegate=self;
    77     
    78     //把操作对象添加到队列中在去
    79     [self.queue addOperation:operation];
    80 
    81 //    NSLog(@"完成显示");
    82     return cell;
    83 }
    84 -(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
    85 {
    86     //返回图片数据给每行对应的cell的imageview.image
    87     //取出tableview中indexPath这一行对应的cell
    88     UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:operation.indexPath];
    89     //显示图片
    90     cell.imageView.image=image;
    91 //    NSLog(@"cell--index--%@---%@",operation.indexPath,[NSThread currentThread]);
    92     //一定要刷新表格
    93     [self.tableView reloadData];
    94     NSLog(@"--%@--",[NSThread currentThread]);
    95 
    96 }
    97 @end
    复制代码

    说明:通过打印可以发现上面的代码存在很大的问题。

    问题1:需要保证一个url对应一个operation对象。

    问题2:下载完需要移除。移除执行完毕的操作。

    问题3:保证一个url对应一个image。
    下面对主控制器中得代码进行改进:
    复制代码
      1 //
      2 //  YYViewController.m
      3 //  01-自定义Operation
      4 //
      5 //  Created by apple on 15-7-29.
      6 //  Copyright (c) 2015年 itcase. All rights reserved.
      7 //
      8 
      9 #import "YYViewController.h"
     10 #import "YYappModel.h"
     11 #import "YYdownLoadOperation.h"
     12 
     13 @interface YYViewController ()<YYdownLoadOperationDelegate>
     14 @property(nonatomic,strong)NSArray *apps;
     15 @property(nonatomic,strong)NSOperationQueue *queue;
     16 @property(nonatomic,strong)NSMutableDictionary *operations;
     17 @property(nonatomic,strong)NSMutableDictionary *images;
     18 
     19 @end
     20 
     21 @implementation YYViewController
     22 #pragma mark- 懒加载apps
     23 -(NSArray *)apps
     24 {
     25     if (_apps==nil) {
     26         NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
     27         NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
     28         
     29         //字典转模型
     30         NSMutableArray *array=[NSMutableArray array];
     31         for (NSDictionary *dict in tempArray) {
     32             YYappModel *app=[YYappModel appModelWithDict:dict];
     33             [array addObject:app];
     34         }
     35         _apps=array;
     36     }
     37     return _apps;
     38 }
     39 
     40 #pragma mark-懒加载queue
     41 -(NSOperationQueue *)queue
     42 {
     43     if (_queue==Nil) {
     44         _queue=[[NSOperationQueue alloc]init];
     45         //设置最大并发数为3
     46         _queue.maxConcurrentOperationCount=3;
     47     }
     48     return _queue;
     49 }
     50 
     51 #pragma mark-懒加载operations
     52 -(NSMutableDictionary *)operations
     53 {
     54     if (_operations==Nil) {
     55         _operations=[NSMutableDictionary dictionary];
     56     }
     57     return _operations;
     58 }
     59 
     60 #pragma mark-懒加载images
     61 -(NSMutableDictionary *)images
     62 {
     63     if (_images==Nil) {
     64         _images=[NSMutableDictionary dictionary];
     65     }
     66     return _images;
     67 }
     68 
     69 #pragma mark-数据源方法
     70 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
     71 {
     72     return self.apps.count;
     73 }
     74 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
     75 {
     76     static NSString *ID=@"ID";
     77     UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
     78     if (cell==nil) {
     79         cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
     80     }
     81     YYappModel *app=self.apps[indexPath.row];
     82     cell.textLabel.text=app.name;
     83     cell.detailTextLabel.text=app.download;
     84     
     85     //保证一个url对应一个image对象
     86     UIImage *image=self.images[app.icon];
     87     if (image) {//缓存中有图片
     88         cell.imageView.image=image;
     89     }else       //  缓存中没有图片,得下载
     90     {
     91         //先设置一张占位图片
     92         cell.imageView.image=[UIImage imageNamed:@"57437179_42489b0"];
     93         YYdownLoadOperation *operation=self.operations[app.icon];
     94         if (operation) {//正在下载
     95             //什么都不做
     96         }else  //当前没有下载,那就创建操作
     97         {
     98             operation=[[YYdownLoadOperation alloc]init];
     99             operation.url=app.icon;
    100             operation.indexPath=indexPath;
    101             operation.delegate=self;
    102             [self.queue addOperation:operation];//异步下载
    103             self.operations[app.icon]=operation;
    104         }
    105     }
    106     
    107 
    108     return cell;
    109 }
    110 -(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
    111 {
    112     //1.移除执行完毕的操作
    113     [self.operations removeObjectForKey:operation.url];
    114     
    115     //2.将图片放到缓存中
    116     self.images[operation.url]=image;
    117 
    118     //3.刷新表格(只刷新下载的那一行)
    119     
    120     [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    121     NSLog(@"--%d--%@--",operation.indexPath.row,[NSThread currentThread]);
    122 
    123 }
    124 @end
    复制代码

    打印查看:

     
  • 相关阅读:
    Spring boot 启动图片
    Spring Cloud 从入门到入门
    理解错误的 Arrays.asList()
    git github 对代码的管理
    【POJ 2154】Color
    CodeForces
    CodeForces
    CodeForces
    CodeForces
    [数据结构]Hash Table(哈希表)
  • 原文地址:https://www.cnblogs.com/kongweiiwei/p/4686040.html
Copyright © 2011-2022 走看看