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

实现效果展示:

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

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

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

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

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

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

YYappModel.h文件

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

YYappModel.m文件

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

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

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

打印查看:

二、自定义NSOperation

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

1.通过代理

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

YYdownLoadOperation.h文件

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

YYdownLoadOperation.m文件

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

主控制器中的业务逻辑:

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

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

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

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

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

打印查看:

iOS多线程编程之自定义NSOperation(转载)的更多相关文章

  1. iOS多线程编程之创建线程(转载)

    一.创建和启动线程简单说明 一个NSThread对象就代表一条线程 (1)创建.启动线程 NSThread *thread = [[NSThread alloc] initWithTarget:sel ...

  2. iOS多线程编程原理及实践

    摘要:iOS开发中,开发者不仅要做好iOS的内存管理,而且如果你的iOS涉及多线程,那你也必须了解iOS编程中对多线程的限制,iOS主线程的堆栈大小为1M,其它线程均为512KB,且这个限制开发者是无 ...

  3. iOS多线程编程指南

    iOS多线程编程指南(拓展篇)(1) 一.Cocoa 在Cocoa上面使用多线程的指南包括以下这些: (1)不可改变的对象一般是线程安全的.一旦你创建了它们,你可以把这些对象在线程间安全的传递.另一方 ...

  4. iOS多线程编程Part 2/3 - NSOperation

    多线程编程Part 1介绍了NSThread以及NSRunLoop,这篇Blog介绍另一种并发编程技术:NSOPeration. NSOperation & NSOperationQueue ...

  5. iOS多线程编程--NSOperation(转)

    这篇文章写得非常不错,基础用法都涉及到了,我把文章提到的例子都写到了demo里面, 原文地址: iOS多线程--彻底学会多线程之『NSOperation』 demo下载:https://github. ...

  6. iOS多线程编程技术之NSThread、Cocoa NSOperation、GCD

    原文出处: 容芳志的博客 简介iOS有三种多线程编程的技术,分别是:(一)NSThread(二)Cocoa NSOperation(三)GCD(全称:Grand Central Dispatch) 这 ...

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

    iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...

  8. IOS高级编程之三:IOS 多线程编程

    多线程的概念在各个操作系统上都会接触到,windows.Linux.mac os等等这些常用的操作系统,都支持多线程的概念. 当然ios中也不例外,但是线程的运行节点可能是我们平常不太注意的. 例如: ...

  9. iOS多线程编程

    废话不多说,直接上干货.先熟悉一下基本知识,然后讲一下常用的两种,NSOperation和GCD. 一.基础概念 进程: 狭义定义:进程是正在运行的程序的实例(an instance of a com ...

随机推荐

  1. laravel 5.3升级5.4

    1)修改 composer 配置文件 composer.json 1.如果你用了 laravel-admin,larvel-admin 版本改 1.4.x-dev 2.laravel 版本改 5.4. ...

  2. Java EE发展史

    前言 最近的这段时间一直在学习Java EE,刚刚完成了从0到1的蜕变,所以顺便整理一下我所了解到的Java EE,给刚入门学习的新人一些头绪,而所谓“启示录”,就是这个意思. 一.Java EE是什 ...

  3. R语言(入门小练习篇)

    问题: 一组学生参加了数学.科学和英语考试.为了给所有的学生确定一个单一的成绩衡量指标,需要将这些科目的成绩组合起来.另外,还想将前20%的学生评定为A,接下来20%的学生评定为B,以此类推.最后,希 ...

  4. 一.jquery.datatables.js表格显示

    2014年8月10日星期日 使用jquery.datatables.js取后台数据. 1.html代码 <table class="dataTables-example"&g ...

  5. 修改JS文件不能及时在页面中体现,需重启浏览器?

    对JS文件做个小小的改动,哪怕是加一句简单的ALERT语句,都要重启浏览器才能看到.你有这样的烦恼吗?怎样不用重启浏览器就能及时体现JS的变化呢? 对浏览器(IE)做如下设置即可:1.点击 工具栏 - ...

  6. update select 多字段

    update Countrys set ( Abbreviation_cn, Abbreviation_en, Two_code,Three_code, Number_code)= (select [ ...

  7. Android中openmax实现框架

    OMX中 OMXNodeInstance 负责创建并维护不同的实例,这些实例是根据上面需求创建的,以node作为唯一标识.这样播放器中每个OMXCodec在OMX服务端都对应有了自己的OMXNodeI ...

  8. 23种设计模式之访问者模式(Visitor)

    访问者模式是一种对象的行为性模式,用于表示一个作用于某对象结构中的各元素的操作,它使得用户可以再不改变各元素的类的前提下定义作用于这些元素的新操作.访问者模式使得增加新的操作变得很容易,但在一定程度上 ...

  9. 关于windows 7系统下开启休眠功能的方法

    今天笔者新装了一个windows 7操作系统,装完后,点击开始按钮.鼠标放到关机处的左边扩展选项时,没有发现休眠选项. 于是开始上网查询解决方法,并将过程记录如下: 首先简单的介绍一下休眠功能:休眠( ...

  10. Linux系统java环境jdk的安装

    在linux环境中jdk的安装有两种方式,一为rpm安装机制,另一种为源码安装(已编译好)因此在ORACLE官网提供两种安装文件,一为rpm格式,另一种为gz格式,两种的安装方式都大同小异的. 1.r ...