ios多线程操作(十二)—— 自定义NSOperation实现网络下载后回调

NSoperation作为一个抽象类,本身不具备封装操作的能力,所以必须使用它的子类来实现多线程操作,但当子类也无法达到我们的需求时,我们可以自定义一个NSoperation的子类,自己写实现方法!
     自定义NSoperation的步骤很简单,只要重写main方法,在里面实现想执行的异步任务,但如果是异步操作,也就无法访问到主线程的自动释放池,所以需要自己手动创建自动释放池!
     现在我们来实现一个需求,自定义一个NSOperation子类,实现网络图片下载,再在主线程上设置图片!
首先需要一个继承自NSOperation的子类,该类提供一个可以实例化操作的方法
#import <UIKit/UIKit.h>

@interface CXWebImageOperation : NSOperation
/**
 *  实例化web图片操作
 */
+ (instancetype)webImageOperationWithUrl:(NSString *)urlString completion:(void(^) (UIImage *image))completion;
@end

其中urlString是提供给控制器设置图片链接的参数,而completion是一个提供给控制器编写执行完下载操作后要执行的代码,image是操作传回来的已下载完的图片对象
再来看一下该类的实现文件,.m文件里面提供了两个私有变量
@interface CXWebImageOperation ()
/**
 *  图片的url
 */
@property (nonatomic,copy) NSString *urlString;
/**
 *  下载完图片后需要执行的代码块
 */
@property (nonatomic,copy) void (^completion)(UIImage *image);

@end

image自定义操作最主要的目的是重写main方法,而main方法里面想要访问到图片链接以及代码块只能通过成员变量!该类提供的类方法实现如下:
+ (instancetype)webImageOperationWithUrl:(NSString *)urlString completion:(void(^) (UIImage *image))completion
{
    CXWebImageOperation *op = [[self alloc] init];
    op.urlString = urlString;
    op.completion = completion;
    return op;
}

为成员变量赋值。
重写main方法
- (void)main
{
    @autoreleasepool {
        
        // 下载图片的耗时操作
        NSURL *url = [NSURL URLWithString:self.urlString];
        NSData *data = [NSData dataWithContentsOfURL:url];
        NSLog(@"已下载 %@",[NSThread currentThread]);
        UIImage *image = [UIImage imageWithData:data];
        
        // 主线程回调,完成操作后通知调用方完成回调
        dispatch_async(dispatch_get_main_queue(), ^{
            
            if (self.completion != nil) {
                self.completion(image);
                
            }
        });
    }
   
}

在控制器里面实现对图片的设置,在这之前,我们需要在storyboard里面添加一个UIImageView控件并拖线进控制器里面
@interface ViewController ()
/**
 *  图片
 */
@property (weak, nonatomic) IBOutlet UIImageView *iconV;
/**
 *  操作队列
 */
@property (nonatomic,strong) NSOperationQueue *queue;
@end

用懒加载的方式初始化队列
- (NSOperationQueue *)queue
{
    if (_queue == nil) {
        _queue = [[NSOperationQueue alloc] init];
    }
    return _queue;
}

初始化操作并执行
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 图片下载操作
    CXWebImageOperation *op = [CXWebImageOperation webImageOperationWithUrl:@"http://p17.qhimg.com/dr/48_48_/t012d281e8ec8e27c06.png" completion:^(UIImage *image) {
     NSLog(@"%@",[NSThread currentThread]);
        // block回调在主线程更新UI
        self.iconV.image = image;
    }];
    // 添加进队列
    [self.queue addOperation:op];
}

此时自定义操作已基本完成
控制台打印结果如下:
技术分享
可以在虚拟机上看到效果如下
技术分享
该图片已从网络下载并展现在屏幕上!
当然以上只是一个简单地自定义操作的演示,且不说调用比较麻烦,光是从队列操作上图片缓存上就没有做任何优化处理!要实现一个完整的网络图片下载操作,还需要一个单例类来进行缓存及操作的优化管理,同时也需要为UIImageView设置一个分类,提供最便捷的图片处理方法!


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。