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

NSoperation作为一个抽象类,本身不具备封装操作的能力,所以必须使用它的子类来实现多线程操作,但当子类也无法达到我们的需求时,我们可以自定义一个NSoperation的子类,自己写实现方法!
     自定义NSoperation的步骤很简单,只要重写main方法,在里面实现想执行的异步任务,但如果是异步操作,也就无法访问到主线程的自动释放池,所以需要自己手动创建自动释放池!
     现在我们来实现一个需求,自定义一个NSOperation子类,实现网络图片下载,再在主线程上设置图片!
首先需要一个继承自NSOperation的子类,该类提供一个可以实例化操作的方法
[objc]  view plain  copy
  1. #import <UIKit/UIKit.h>  
  2.   
  3. @interface CXWebImageOperation : NSOperation  
  4. /** 
  5.  *  实例化web图片操作 
  6.  */  
  7. + (instancetype)webImageOperationWithUrl:(NSString *)urlString completion:(void(^) (UIImage *image))completion;  
  8. @end  

其中urlString是提供给控制器设置图片链接的参数,而completion是一个提供给控制器编写执行完下载操作后要执行的代码,image是操作传回来的已下载完的图片对象
再来看一下该类的实现文件,.m文件里面提供了两个私有变量
[objc]  view plain  copy
  1. @interface CXWebImageOperation ()  
  2. /** 
  3.  *  图片的url 
  4.  */  
  5. @property (nonatomic,copyNSString *urlString;  
  6. /** 
  7.  *  下载完图片后需要执行的代码块 
  8.  */  
  9. @property (nonatomic,copyvoid (^completion)(UIImage *image);  
  10.   
  11. @end  

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

为成员变量赋值。
重写main方法
[objc]  view plain  copy
  1. - (void)main  
  2. {  
  3.     @autoreleasepool {  
  4.           
  5.         // 下载图片的耗时操作  
  6.         NSURL *url = [NSURL URLWithString:self.urlString];  
  7.         NSData *data = [NSData dataWithContentsOfURL:url];  
  8.         NSLog(@"已下载 %@",[NSThread currentThread]);  
  9.         UIImage *image = [UIImage imageWithData:data];  
  10.           
  11.         // 主线程回调,完成操作后通知调用方完成回调  
  12.         dispatch_async(dispatch_get_main_queue(), ^{  
  13.               
  14.             if (self.completion != nil) {  
  15.                 self.completion(image);  
  16.                   
  17.             }  
  18.         });  
  19.     }  
  20.      
  21. }  

在控制器里面实现对图片的设置,在这之前,我们需要在storyboard里面添加一个UIImageView控件并拖线进控制器里面
[objc]  view plain  copy
  1. @interface ViewController ()  
  2. /** 
  3.  *  图片 
  4.  */  
  5. @property (weak, nonatomic) IBOutlet UIImageView *iconV;  
  6. /** 
  7.  *  操作队列 
  8.  */  
  9. @property (nonatomic,strongNSOperationQueue *queue;  
  10. @end  

用懒加载的方式初始化队列
[objc]  view plain  copy
  1. - (NSOperationQueue *)queue  
  2. {  
  3.     if (_queue == nil) {  
  4.         _queue = [[NSOperationQueue alloc] init];  
  5.     }  
  6.     return _queue;  
  7. }  

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

此时自定义操作已基本完成
控制台打印结果如下:

可以在虚拟机上看到效果如下

该图片已从网络下载并展现在屏幕上!
当然以上只是一个简单地自定义操作的演示,且不说调用比较麻烦,光是从队列操作上图片缓存上就没有做任何优化处理!要实现一个完整的网络图片下载操作,还需要一个单例类来进行缓存及操作的优化管理,同时也需要为UIImageView设置一个分类,提供最便捷的图片处理方法!

你可能感兴趣的:(ios多线程操作(十二)—— 自定义NSOperation实现网络下载后回调)