iOS开发之自定义NSOperation
来源:互联网 发布:不抄袭的网络作家 编辑:程序博客网 时间:2024/05/16 06:36
本文主要介绍通过自定义NSOperation实现图片异步下载功能。下面直接上代码。
1. 先把程序的框架搭建起来:
window的主视图式导航栏控制器UINavigationController,导航栏控制器UINavigationController的根视图是UITableView。效果如下:
2. 向UITableView上设置数据,这里加载的是plist文件:
3. 将plist文件中的数据转化成模型,创建模型HXApp。
HXApp.h
#import <Foundation/Foundation.h>@interface HXApp : NSObject/** * 应用名称 */@property (nonatomic, copy) NSString *name;/** * 应用图标 */@property (nonatomic, copy) NSString *icon;/** * 应用下载量 */@property (nonatomic, copy) NSString *download;+ (instancetype)appWithDict:(NSDictionary *)dict;- (instancetype)initWithDict:(NSDictionary *)dict;@endHXApp.m
#import "HXApp.h"@implementation HXApp+ (instancetype)appWithDict:(NSDictionary *)dict { return [[self alloc] initWithDict:dict];}- (instancetype)initWithDict:(NSDictionary *)dict { HXApp *app = [[HXApp alloc] init]; [app setValuesForKeysWithDictionary:dict]; return app;}@end
4. 在控制器中读取plist文件数据,创建一个模型数组apps(懒加载),转化成模型后添加到数组中;
- (NSMutableArray *)apps { if (_apps == nil) { // 读取数据 NSArray *appArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]]; // 将数据中的字典转化成模型 NSMutableArray *apps = [NSMutableArray array]; for (NSDictionary *appDict in appArray) { HXApp *app = [HXApp appWithDict:appDict]; [apps addObject:app]; } _apps = apps; } return _apps;}
5. 实现tableView的数据源方法:
#pragma mark - tableView datasource- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.apps.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 创建cell static NSString *identifier = @"APP"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; } // 设置数据 HXApp *app = self.apps[indexPath.row]; cell.textLabel.text = app.name; cell.detailTextLabel.text = app.download; <span style="color:#FF0000;">// 显示图片(重点介绍该部分)</span> return cell;}
6. 下载图片,我们通过自定义的NSOperation(HXDownLoadOperation)来完成,我们让HXDownLoadOperation专门用来下载图片。HXDownLoadOperation要先下载图片就得知道url,又因为它是下载cell中的图片,还要知道是哪个cell的图片。
HXDownLoadOperation.h
#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@interface HXDownLoadOperation : NSOperation/** * 下载路径 */@property (nonatomic, copy) NSString *url;/** * 下载的图片索引 */@property (nonatomic, strong) NSIndexPath *indexPath;@end
7. 在cellForRowAtIndexPath:方法中添加下面代码,并有思路:
<span style="color:#FF0000;">// 显示图片</span><span style="color:#FF0000;">(重点介绍该部分)</span> // 1.根据图片url,向字典images中取出对应的image UIImage *image = [self.urlsWithImages valueForKey:app.icon]; // 2.判断image是否存在 if (image) {// image存在 cell.imageView.image = image; }else {// image不存在 // 占位图片 cell.imageView.image = [UIImage imageNamed:@"000"]; // 3.下载图片 // 根据图片url,向字典operations中取出对应的操作operation HXDownLoadOperation *operation = [self.urlsWithOperations valueForKey:app.icon]; // 4.判断operation下载操作是否存在(即是否正在下载该图片) if (operation) {// operation下载操作存在(即正在下载该图片,不作任何处理) }else {// operation下载操作不存在(即还没有下载过该图片) // 创建下载操作 operation = [[HXDownLoadOperation alloc] init]; // 图片url operation.url = app.icon; operation.delegate = self; operation.indexPath = indexPath; // 添加到队列中(异步执行) [self.queue addOperation:operation];// 调用该方法会执行start方法(异步),在start方法中会调用队列的main方法 // 将新的下载操作添加到字典operations中 // self.urlsWithOperations[app.icon] = operation; [self.urlsWithOperations setValue:operation forKey:app.icon]; } }
8. HXDownLoadOperation知道图片的url和该图片在cell上的位置后,重写main方法,在main方法中下载完图片,要通知cell显示图片,所在此时的HXDownLoadOperation.h文件中:
#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@class HXDownLoadOperation;@protocol HXDownLoadOperationDelegate <NSObject>@optional/** * 执行完系在操作后,会调用该代理方法 * * @param operation 下载操作 * @param image 下载的图片 */- (void)downLoadOperation:(HXDownLoadOperation *)operation didFinishedDownLoad:(UIImage *)image;@end@interface HXDownLoadOperation : NSOperation@property (nonatomic, weak) id<HXDownLoadOperationDelegate> delegate;/** * 下载路径 */@property (nonatomic, copy) NSString *url;/** * 下载的图片索引 */@property (nonatomic, strong) NSIndexPath *indexPath;@endHXDownLoadOperation.m
/** * 重写main方法,执行下载的操作 */- (void)main { NSURL *downLoadUrl = [NSURL URLWithString:self.url]; NSData *imageData = [NSData dataWithContentsOfURL:downLoadUrl]; UIImage *image = [UIImage imageWithData:imageData]; // 下载完成后,通知代理 if ([self.delegate respondsToSelector:@selector(downLoadOperation:didFinishedDownLoad:)]) { // 在主线程中通知代理 dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate downLoadOperation:self didFinishedDownLoad:image]; }); }}
9. 将控制器设置为HXDownLoadOperation的代理,并实现代理方法:
#pragma mark - HXDownLoadOperationDelegate- (void)downLoadOperation:(HXDownLoadOperation *)operation didFinishedDownLoad:(UIImage *)image { // 执行完下载操作,将该下载操作从字典operations中移除(防止下载失败等问题) [self.urlsWithOperations removeObjectForKey:operation.url]; // 向字典images中添加下载之后的图片 if (image) {// 该判断是防止图片路径无效等问题 self.urlsWithImages[operation.url] = image; // 刷新表格(局部刷新) [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone]; }}
10. 到此图片下载的步骤已经基本完成,下载完的图片不会在重新下载,所以在滚动cell的时候不会在去下载之前的图片。现在对这个项目做一个小优化。
// 细节优化(当滚动表格的时候,停止下载图片,不滚动的时候,再继续下载)#pragma mark - UIScrollViewDelegate- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { // 当开始拖拽的时候,通知cell停止下载图片 [self.queue setSuspended:YES]; }- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { // 当停止拖拽的时候,通知cell继续下载图片 [self.queue setSuspended:NO];}
最后运行看一下效果:
本文的内容介绍完了,主要是想总结一下自定义NSOperation的步骤,和实现图片下载的思路。其实关于图片下载有一个很牛X的第三方类库:SDWebImage。
- iOS开发之自定义NSOperation
- iOS开发 自定义NSOPeration
- iOS开发多线程-自定义NSOperation
- iOS开发实践之cell下载图片(自定义NSOperation)
- IOS多线程开发之NSOperation
- iOS开发 - 多线程之NSOperation
- iOS多线程开发之NSOperation
- iOS开发多线程篇—自定义NSOperation
- iOS开发多线程篇—自定义NSOperation
- iOS开发多线程篇—自定义NSOperation
- iOS开发多线程篇—自定义NSOperation
- iOS开发 自定义并发NSOperation实战
- IOS多线程之NSOperation(自定义)
- IOS开发—多线程之NSOperation介绍
- iOS 并行开发技术之 NSOperation && GCD
- iOS多线程与网络开发之NSOperation
- iOS多线程开发系列之(二)NSOperation
- iOS开发:多线程之NSThread、NSOperation
- ViewRotImpl
- 安卓必备五个常用代码片段整理
- listView中添加checkBox按键,点击是否选中处理。
- 锐捷网络频繁掉线
- yii2安装(windows & linux)
- iOS开发之自定义NSOperation
- socket服务端和client端
- 系统盘datePicker、调整Nav后退按钮位置调整,电话短信邮件分享
- 二、C++11多线程std::thread的简单使用(下)
- 读写INI文件
- 学习资料-好久没写了
- java中判断字符串是否为纯数字
- 怎样让Git忽略当前已经更改的文件
- poj 2361 Tic Tac Toe 五子棋模拟