zoukankan      html  css  js  c++  java
  • iOS开发多线程篇—自定义NSOperation

    iOS开发多线程篇—自定义NSOperation

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

    实现效果展示:

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

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

    复制代码
     1 //
     2 //  YYViewController.h
     3 //  01-自定义Operation
     4 //
     5 //  Created by apple on 14-6-26.
     6 //  Copyright (c) 2014年 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-6-26.
     6 //  Copyright (c) 2014年 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 14-6-26.
     6 //  Copyright (c) 2014年 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-6-26.
     6 //  Copyright (c) 2014年 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 14-6-26.
     6 //  Copyright (c) 2014年 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 14-6-26.
     6 //  Copyright (c) 2014年 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 14-6-26.
      6 //  Copyright (c) 2014年 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
    复制代码

    打印查看:

     
     
  • 相关阅读:
    [BJOI2019] 光线
    C# 从零开始写 SharpDx 应用 笔刷
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    PowerShell 拿到显卡信息
    PowerShell 拿到显卡信息
    win10 uwp 如何使用DataTemplate
    win10 uwp 如何使用DataTemplate
  • 原文地址:https://www.cnblogs.com/187n/p/5056714.html
Copyright © 2011-2022 走看看