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;@end
HXApp.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;@end
HXDownLoadOperation.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。









0 0
原创粉丝点击