zoukankan      html  css  js  c++  java
  • IOS-多线程(NSOperation)

     一、基础用法

      1 //
      2 //  ViewController.m
      3 //  IOS_0120_NSOperation
      4 //
      5 //  Created by ma c on 16/1/20.
      6 //  Copyright © 2016年 博文科技. All rights reserved.
      7 //
      8 
      9 #import "ViewController.h"
     10 
     11 @interface ViewController ()<UITableViewDelegate>
     12 
     13 @property (nonatomic, strong) UIImageView *imageView;
     14 
     15 @end
     16 
     17 @implementation ViewController
     18 /*
     19  一、简介
     20  1.NSOperation的作用
     21  配合使用NSOperation和NSOperationQueue也能实现多线程编程
     22  
     23  2.NSOperation和NSOperationQueue实现多线程的具体步骤
     24  1>先将需要执行的操作封装到一个NSOperation对象中
     25  2>然后将NSOperation对象添加到NSOperationQueue中
     26  3>系统会自动将NSOperationQueue中的NSOperation取出来
     27  4>将取出的NSOperation封装的操作放到一条新线程中执行
     28  
     29  二、NSOperation的子类
     30  1.NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
     31  
     32  2.使用NSOperation子类的方式有3种
     33  1>NSInvocationOperation
     34  2>NSBlockOperation
     35  3>自定义子类继承NSOperation,实现内部相应的方法
     36  
     37  三、具体使用
     38  1.NSInvocationOperation
     39  1>创建NSInvocationOperation对象
     40  - (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
     41  
     42  2>调用start方法开始执行操作
     43  - (void)start;
     44  一旦执行操作,就会调用target的sel方法
     45  
     46  3>注意
     47  默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
     48  只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
     49 
     50  2.NSBlockOperation
     51  1>创建NSBlockOperation对象
     52  + (id)blockOperationWithBlock:(void (^)(void))block;
     53  
     54  2>通过addExecutionBlock:方法添加更多的操作
     55  - (void)addExecutionBlock:(void (^)(void))block;
     56  
     57  3>注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
     58 
     59 三、NSOperationQueue
     60  1.NSOperationQueue的作用
     61  NSOperation可以调用start方法来执行任务,但默认是同步执行的
     62  如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
     63  
     64  2.添加操作到NSOperationQueue中
     65  - (void)addOperation:(NSOperation *)op;
     66  - (void)addOperationWithBlock:(void (^)(void))block;
     67 
     68  四、最大并发数
     69  1.什么是并发数
     70  同时执行的任务数
     71  比如,同时开3个线程执行3个任务,并发数就是3
     72  
     73  2.最大并发数的相关方法
     74  - (NSInteger)maxConcurrentOperationCount;
     75  - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
     76 
     77  五、队列的取消、暂停、恢复
     78  取消队列的所有操作
     79  - (void)cancelAllOperations;
     80  提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
     81  
     82  暂停和恢复队列
     83  - (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
     84  - (BOOL)isSuspended;
     85 
     86  六、操作优先级
     87  1.设置NSOperation在queue中的优先级,可以改变操作的执行优先级
     88  - (NSOperationQueuePriority)queuePriority;
     89  - (void)setQueuePriority:(NSOperationQueuePriority)p;
     90  
     91  2.优先级的取值
     92  NSOperationQueuePriorityVeryLow = -8L,
     93  NSOperationQueuePriorityLow = -4L,
     94  NSOperationQueuePriorityNormal = 0,
     95  NSOperationQueuePriorityHigh = 4,
     96  NSOperationQueuePriorityVeryHigh = 8
     97  
     98  七、操作的监听
     99  1.可以监听一个操作的执行完毕
    100  - (void (^)(void))completionBlock;
    101  - (void)setCompletionBlock:(void (^)(void))block;
    102  
    103  八、操作的依赖
    104  NSOperation之间可以设置依赖来保证执行顺序
    105  比如一定要让操作A执行完后,才能执行操作B,可以这么写
    106  [operationB addDependency:operationA]; // 操作B依赖于操作A
    107  可以在不同queue的NSOperation之间创建依赖关系
    108  
    109  注意:不能相互依赖 比如A依赖B,B依赖A
    110 
    111  九、第三方框架的使用建议
    112  1.用第三方框架的目的
    113  1> 开发效率:快速开发,人家封装好的一行代码顶自己写的N行
    114  2> 为了使用这个功能最牛逼的实现
    115  
    116  2.第三方框架过多,很多坏处(忽略不计)
    117  1> 管理、升级、更新
    118  2> 第三方框架有BUG,等待作者解决
    119  3> 第三方框架的作者不幸去世、停止更新(潜在的BUG无人解决)
    120  4> 感觉:自己好水
    121  
    122  3.比如
    123  流媒体:播放在线视频、音频(边下载边播放)
    124  非常了解音频、视频文件的格式
    125  每一种视频都有自己的解码方式(CC++)
    126  
    127  4.总结
    128  1> 站在巨人的肩膀上编程
    129  2> 没有关系,使劲用那么比较稳定的第三方框架
    130  
    131 十、SDWebImage
    132  1.什么是SDWebImage
    133  iOS中著名的牛逼的网络图片处理框架
    134  包含的功能:图片下载、图片缓存、下载进度监听、gif处理等等
    135  用法极其简单,功能十分强大,大大提高了网络图片的处理效率
    136  国内超过90%的iOS项目都有它的影子
    137  2.项目地址
    138  https://github.com/rs/SDWebImage
    139  
    140  1> 常用方法
    141  - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
    142  - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
    143  - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;
    144  - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
    145  
    146  2> 内存处理:当app接收到内存警告时
    147  当app接收到内存警告
    148  - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
    149  {
    150  SDWebImageManager *mgr = [SDWebImageManager sharedManager];
    151  
    152  // 1.取消正在下载的操作
    153  [mgr cancelAll];
    154  
    155  // 2.清除内存缓存
    156  [mgr.imageCache clearMemory];
    157  }
    158  3> SDWebImageOptions
    159  * SDWebImageRetryFailed : 下载失败后,会自动重新下载
    160  * SDWebImageLowPriority : 当正在进行UI交互时,自动暂停内部的一些下载操作
    161  * SDWebImageRetryFailed | SDWebImageLowPriority : 拥有上面2个功能
    162  
    163  十一、自定义NSOperation
    164  自定义NSOperation的步骤很简单
    165  重写- (void)main方法,在里面实现想执行的任务
    166  
    167  重写- (void)main方法的注意点
    168  自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
    169  经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
    170 
    171  */
    172 
    173 - (void)viewDidLoad {
    174     [super viewDidLoad];
    175     
    176 //    [self useNSInvocationOperation];
    177 //    [self useBaseNSBlockOperation];
    178 //    [self useNSBlockOperation];
    179 //    [self useNSOperationQueue];
    180 //    [self useAddDependency];
    181     
    182     self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(30, 200, 340, 200)];
    183     [self.view addSubview:self.imageView];
    184     [self communicate];
    185     
    186 }
    187 
    188 #pragma mark - 通讯
    189 - (void)communicate
    190 {
    191     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    192     //取消队列所有操作
    193 //    [queue cancelAllOperations];
    194 //    NSLog(@"didCancelAllOperations");
    195     //暂停队列
    196     [queue setSuspended:YES];
    197     //恢复队列
    198     [queue setSuspended:NO];
    199     //异步下载图片
    200     [queue addOperationWithBlock:^{
    201         NSURL *url = [NSURL URLWithString:@"http://images.haiwainet.cn/2016/0113/20160113015030150.jpg"];
    202         NSData *data = [[NSData alloc] initWithContentsOfURL:url];
    203         UIImage *image = [UIImage imageWithData:data];
    204         //回到主线程,显示图片
    205         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    206             self.imageView.image = image;
    207         }];
    208     }];
    209 }
    210 
    211 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    212 {
    213 //    [queue setSuspended:YES]; //暂停队列中所有任务
    214 }
    215 
    216 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    217 {
    218 //    [queue setSuspended:NO]; //恢复队列中所有任务
    219 }
    220 
    221 #pragma mark - 依赖
    222 - (void)useAddDependency
    223 {
    224     /*三个异步执行操作:操作C依赖于操作B,操作B依赖于操作A*/
    225     
    226     //创建一个队列
    227     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    228     
    229     NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
    230         NSLog(@"A1--------%@",[NSThread currentThread]);
    231     }];
    232     [operationA addExecutionBlock:^{
    233         NSLog(@"A2--------%@",[NSThread currentThread]);
    234     }];
    235     [operationA setCompletionBlock:^{
    236         NSLog(@"依赖于A--------%@",[NSThread currentThread]);
    237 
    238     }];
    239     NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
    240         NSLog(@"B--------%@",[NSThread currentThread]);
    241     }];
    242     NSBlockOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{
    243         NSLog(@"C--------%@",[NSThread currentThread]);
    244     }];
    245     //设置依赖
    246     [operationB addDependency:operationA];
    247     [operationC addDependency:operationB];
    248     
    249     [queue addOperation:operationA];
    250     [queue addOperation:operationB];
    251     [queue addOperation:operationC];
    252 }
    253 
    254 #pragma mark - 队列中直接添加任务
    255 - (void)useNSOperationQueue
    256 {
    257     //1.创建operation的时候,添加一个任务
    258     NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    259         NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
    260     }];
    261     NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    262         NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
    263     }];
    264 
    265     //2.创建队列(非主队列)会自动异步执行任务,并发
    266     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    267     
    268     //3.设置最大并发数
    269     queue.maxConcurrentOperationCount = 2;
    270     
    271     //4.添加操作到队列中
    272     [queue addOperation:operation1];
    273     [queue addOperation:operation2];
    274     
    275     [queue addOperationWithBlock:^{
    276         NSLog(@"--------下载图片3--------%@",[NSThread currentThread]);
    277     }];
    278 }
    279 
    280 #pragma mark - 多操作添加到队列
    281 - (void)useNSBlockOperation
    282 {
    283     //创建operation的时候,添加一个任务
    284     NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    285         NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
    286     }];
    287     NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    288         NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
    289     }];
    290     //创建队列
    291     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    292     //主队列
    293 //    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    294     //添加操作到队列中
    295     [queue addOperation:operation1];
    296     [queue addOperation:operation2];
    297     
    298     //[operation start];
    299 }
    300 
    301 #pragma mark - NSBlockOperation
    302 - (void)useBaseNSBlockOperation
    303 {
    304     //创建operation的时候,添加一个任务
    305 //    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    306 //        NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
    307 //    }];
    308     
    309     NSBlockOperation *operation = [[NSBlockOperation alloc] init];
    310     //操作中添加任务
    311     [operation addExecutionBlock:^{
    312         NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
    313     }];
    314     [operation addExecutionBlock:^{
    315         NSLog(@"--------下载图片3--------%@",[NSThread currentThread]);
    316     }];
    317     
    318     //任务大于1,才会异步执行
    319     [operation start];
    320 }
    321 
    322 #pragma mark - NSInvocationOperation
    323 - (void)useNSInvocationOperation
    324 {
    325     //创建队列
    326     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    327     //创建操作
    328     NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
    329     
    330     //opreation直接调用start,是同步执行(在当前线程执行操作)
    331     //[operation start];
    332     
    333     //添加操作到队列中,会自动异步执行
    334     [queue addOperation:operation];
    335 }
    336 
    337 - (void)download
    338 {
    339     NSLog(@"download-------%@",[NSThread currentThread]);
    340 }
    341 
    342 - (void)didReceiveMemoryWarning {
    343     [super didReceiveMemoryWarning];
    344     // Dispose of any resources that can be recreated.
    345 }
    346 
    347 @end

     二、防止重复下载,与沙盒缓存

     1 //
     2 //  BWApp.h
     3 //  IOS_0120_NSOperation防止重复下载
     4 //
     5 //  Created by ma c on 16/1/20.
     6 //  Copyright © 2016年 博文科技. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 
    11 @interface BWApp : NSObject
    12 
    13 @property (nonatomic, copy) NSString *name;
    14 @property (nonatomic, copy) NSString *download;
    15 @property (nonatomic, copy) NSString *icon;
    16 
    17 + (instancetype)appWithDict:(NSDictionary *)dict;
    18 
    19 @end
    20 
    21 //
    22 //  BWApp.m
    23 //  IOS_0120_NSOperation防止重复下载
    24 //
    25 //  Created by ma c on 16/1/20.
    26 //  Copyright © 2016年 博文科技. All rights reserved.
    27 //
    28 
    29 #import "BWApp.h"
    30 
    31 @implementation BWApp
    32 
    33 + (instancetype)appWithDict:(NSDictionary *)dict
    34 {
    35     BWApp *app = [[self alloc] init];
    36     [app setValuesForKeysWithDictionary:dict];
    37     return app;
    38 }
    39 
    40 @end
      1 //
      2 //  BWTableViewController.m
      3 //  IOS_0120_NSOperation防止重复下载
      4 //
      5 //  Created by ma c on 16/1/20.
      6 //  Copyright © 2016年 博文科技. All rights reserved.
      7 //
      8 
      9 #import "BWTableViewController.h"
     10 #import "BWApp.h"
     11 
     12 #define appImageCachesPath(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]]
     13 
     14 @interface BWTableViewController ()
     15 
     16 //所有应用数据
     17 @property (nonatomic, strong) NSMutableArray *appsArray;
     18 //存放所有下载操作的队列
     19 @property (nonatomic, strong) NSOperationQueue *queue;
     20 //存放所有下载操作(url是key,operation对象是value)
     21 @property (nonatomic, strong) NSMutableDictionary *operationDict;
     22 //缓存图片
     23 @property (nonatomic, strong) NSMutableDictionary *imageDict;
     24 
     25 @end
     26 
     27 @implementation BWTableViewController
     28 
     29 #pragma mark - 懒加载
     30 - (NSMutableArray *)appsArray
     31 {
     32     if (!_appsArray) {
     33         NSMutableArray *appArr = [[NSMutableArray alloc] init];
     34         
     35         NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];
     36         
     37         NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
     38         
     39         for (NSDictionary *dict in dictArr) {
     40             
     41             BWApp *app = [BWApp appWithDict:dict];
     42             [appArr addObject:app];
     43         }
     44         _appsArray = appArr;
     45     }
     46     return _appsArray;
     47 }
     48 
     49 - (NSOperationQueue *)queue
     50 {
     51     if (!_queue) {
     52         _queue = [[NSOperationQueue alloc] init];
     53     }
     54     return _queue;
     55 }
     56 
     57 - (NSMutableDictionary *)operationDict
     58 {
     59     if (!_operationDict) {
     60         _operationDict = [[NSMutableDictionary alloc] init];
     61     }
     62     return _operationDict;
     63 }
     64 
     65 - (NSMutableDictionary *)imageDict
     66 {
     67     if (!_imageDict) {
     68         _imageDict = [[NSMutableDictionary alloc] init];
     69     }
     70     return _imageDict;
     71 }
     72 
     73 #pragma mark - 初始化
     74 - (void)viewDidLoad {
     75     [super viewDidLoad];
     76     
     77 }
     78 
     79 - (void)didReceiveMemoryWarning
     80 {
     81     [super didReceiveMemoryWarning];
     82     
     83     //移除所有下载操作
     84     [self.queue cancelAllOperations];
     85     [self.operationDict removeAllObjects];
     86     //移除所有图片缓存
     87     [self.imageDict removeAllObjects];
     88 }
     89 
     90 
     91 #pragma mark - Table view data source
     92 
     93 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
     94     
     95     return 1;
     96 }
     97 
     98 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     99 
    100     return self.appsArray.count;
    101 }
    102 
    103 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    104     static NSString *cellID = @"cellID";
    105     
    106     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    107     
    108     if (!cell) {
    109         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
    110     }
    111     //取出模型
    112     BWApp *app = [self.appsArray objectAtIndex:indexPath.row];
    113     
    114     cell.textLabel.text = app.name;
    115     cell.detailTextLabel.text = app.download;
    116     
    117     //先从imageDict缓存中取出图片url对应的image
    118     UIImage *image = self.imageDict[app.icon];
    119     
    120     if (image) { //说明图片已经下载成功过
    121         cell.imageView.image = image;
    122     }
    123     else //说明图片未下载(没有缓存)
    124     {
    125         //获取caches路径,拼接文件路径
    126         NSString *filePath = appImageCachesPath(app.icon);
    127         
    128         NSData *data = [NSData dataWithContentsOfFile:filePath];
    129         
    130         if (data) { //沙盒中存在这个图片
    131             cell.imageView.image = [UIImage imageWithData:data];
    132         }
    133         else{
    134             //显示占位图片
    135             cell.imageView.image = [UIImage imageNamed:@"placeholder"];
    136         }
    137         
    138         [self download:app.icon andIndexPath:indexPath];
    139     }
    140     return cell;
    141 }
    142 
    143 - (void)download:(NSString *)imageUrl andIndexPath:(NSIndexPath *)indexPath
    144 {
    145     //取出当前图片对应的下载操作(operation对象)
    146     NSBlockOperation *operation = self.operationDict[imageUrl];
    147     
    148     if (operation)  return;
    149     
    150 //    __weak BWTableViewController *vc = self;
    151     __weak typeof(self) appVC = self;
    152     
    153     //创建操作,下载图片
    154     operation = [NSBlockOperation blockOperationWithBlock:^{
    155         NSURL *url = [NSURL URLWithString:imageUrl];
    156         NSData *data = [NSData dataWithContentsOfURL:url];
    157         UIImage *image = [UIImage imageWithData:data];
    158         
    159         //回到主线程
    160         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    161 
    162             //判断图片是否存在
    163             if (image) {
    164                 //存放图片到字典中
    165                 appVC.imageDict[imageUrl] = image;
    166 #warning 沙盒缓存
    167                 //将图片存入沙盒之中 UIImage --> NSData --> File(文件)
    168                 NSData *data = UIImagePNGRepresentation(image);
    169                 
    170 //                //获取caches路径
    171 //                NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    172 //                
    173 //                //拼接文件路径
    174 //                NSString *fileName = [imageUrl lastPathComponent];
    175 //                NSString *filePath = [cachesPath stringByAppendingPathComponent:fileName];
    176                 
    177                 //写入缓存
    178                 [data writeToFile:appImageCachesPath(imageUrl) atomically:YES];
    179                 
    180                 //UIImageJPEGRepresentation(UIImage * _Nonnull image, CGFloat compressionQuality)
    181             }
    182             //从字典中移除下载操作
    183             [appVC.operationDict removeObjectForKey:imageUrl];
    184             //刷新表格
    185             //[self.tableView reloadData];
    186             [appVC.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
    187         }];
    188     }];
    189     //添加操作到队列中
    190     [appVC.queue addOperation:operation];
    191     //添加操作到字典中(为了解决重复下载)
    192     appVC.operationDict[imageUrl] = operation;
    193 }
    194 //保证图片只下载过一次
    195 //当用户开始拖拽表格时
    196 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    197 {
    198     //暂停下载
    199     [self.queue setSuspended:YES];
    200 }
    201 //用户停止拖拽表格时
    202 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    203 {
    204     //恢复下载
    205     [self.queue setSuspended:NO];
    206 }
    207 
    208 
    209 @end

    三、自定义NSOperation

     1 //
     2 //  BWApp.h
     3 //  IOS_0120_NSOperation防止重复下载
     4 //
     5 //  Created by ma c on 16/1/20.
     6 //  Copyright © 2016年 博文科技. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 
    11 @interface BWApp : NSObject
    12 
    13 @property (nonatomic, copy) NSString *name;
    14 @property (nonatomic, copy) NSString *download;
    15 @property (nonatomic, copy) NSString *icon;
    16 
    17 + (instancetype)appWithDict:(NSDictionary *)dict;
    18 
    19 @end
    20 
    21 
    22 //
    23 //  BWApp.m
    24 //  IOS_0120_NSOperation防止重复下载
    25 //
    26 //  Created by ma c on 16/1/20.
    27 //  Copyright © 2016年 博文科技. All rights reserved.
    28 //
    29 
    30 #import "BWApp.h"
    31 
    32 @implementation BWApp
    33 
    34 + (instancetype)appWithDict:(NSDictionary *)dict
    35 {
    36     BWApp *app = [[self alloc] init];
    37     [app setValuesForKeysWithDictionary:dict];
    38     return app;
    39 }
    40 
    41 @end
     1 //
     2 //  BWDownloadOperation.h
     3 //  IOS_0120_NSOperation防止重复下载
     4 //
     5 //  Created by ma c on 16/1/21.
     6 //  Copyright © 2016年 博文科技. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 #import <UIKit/UIKit.h>
    11 
    12 @class BWDownloadOperation;
    13 
    14 @protocol BWDownloadOperationDelegate <NSObject>
    15 
    16 @optional
    17 - (void)downloadOperation:(BWDownloadOperation *)operation didFinishDownload:(UIImage *)image;
    18 
    19 @end
    20 
    21 @interface BWDownloadOperation : NSOperation
    22 
    23 @property (nonatomic, copy) NSString *imageUrl;
    24 @property (nonatomic, strong) NSIndexPath *indexPath;
    25 
    26 @property (nonatomic, weak) id<BWDownloadOperationDelegate> delegate;
    27 
    28 
    29 @end
    30 
    31 
    32 //
    33 //  BWDownloadOperation.m
    34 //  IOS_0120_NSOperation防止重复下载
    35 //
    36 //  Created by ma c on 16/1/21.
    37 //  Copyright © 2016年 博文科技. All rights reserved.
    38 //
    39 
    40 #import "BWDownloadOperation.h"
    41 
    42 @implementation BWDownloadOperation
    43 
    44 - (void)main
    45 {
    46     @autoreleasepool {
    47         
    48         if (self.isCancelled)  return;
    49         
    50         //创建操作,下载图片
    51         NSURL *url = [NSURL URLWithString:self.imageUrl];
    52         NSData *data = [NSData dataWithContentsOfURL:url];
    53         UIImage *image = [UIImage imageWithData:data];
    54         
    55         if (self.isCancelled)  return;
    56 
    57         //回到主线程
    58         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    59             if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) {
    60                 [self.delegate downloadOperation:self didFinishDownload:image];
    61             }
    62         }];
    63     }
    64 }
    65 @end
      1 //
      2 //  BWTableViewController.m
      3 //  IOS_0120_NSOperation防止重复下载
      4 //
      5 //  Created by ma c on 16/1/20.
      6 //  Copyright © 2016年 博文科技. All rights reserved.
      7 //
      8 
      9 #import "BWTableViewController.h"
     10 #import "BWApp.h"
     11 #import "BWDownloadOperation.h"
     12 
     13 #define appImageCachesPath(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]]
     14 
     15 @interface BWTableViewController ()<BWDownloadOperationDelegate>
     16 
     17 //所有应用数据
     18 @property (nonatomic, strong) NSMutableArray *appsArray;
     19 //存放所有下载操作的队列
     20 @property (nonatomic, strong) NSOperationQueue *queue;
     21 //存放所有下载操作(url是key,operation对象是value)
     22 @property (nonatomic, strong) NSMutableDictionary *operationDict;
     23 //缓存图片
     24 @property (nonatomic, strong) NSMutableDictionary *imageDict;
     25 
     26 @end
     27 
     28 @implementation BWTableViewController
     29 
     30 #pragma mark - 懒加载
     31 - (NSMutableArray *)appsArray
     32 {
     33     if (!_appsArray) {
     34         NSMutableArray *appArr = [[NSMutableArray alloc] init];
     35         
     36         NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];
     37         
     38         NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
     39         
     40         for (NSDictionary *dict in dictArr) {
     41             
     42             BWApp *app = [BWApp appWithDict:dict];
     43             [appArr addObject:app];
     44         }
     45         _appsArray = appArr;
     46     }
     47     return _appsArray;
     48 }
     49 
     50 - (NSOperationQueue *)queue
     51 {
     52     if (!_queue) {
     53         _queue = [[NSOperationQueue alloc] init];
     54     }
     55     return _queue;
     56 }
     57 
     58 - (NSMutableDictionary *)operationDict
     59 {
     60     if (!_operationDict) {
     61         _operationDict = [[NSMutableDictionary alloc] init];
     62     }
     63     return _operationDict;
     64 }
     65 
     66 - (NSMutableDictionary *)imageDict
     67 {
     68     if (!_imageDict) {
     69         _imageDict = [[NSMutableDictionary alloc] init];
     70     }
     71     return _imageDict;
     72 }
     73 
     74 #pragma mark - 初始化
     75 - (void)viewDidLoad {
     76     [super viewDidLoad];
     77     
     78 }
     79 
     80 - (void)didReceiveMemoryWarning
     81 {
     82     [super didReceiveMemoryWarning];
     83     
     84     //移除所有下载操作
     85     [self.queue cancelAllOperations];
     86     [self.operationDict removeAllObjects];
     87     //移除所有图片缓存
     88     [self.imageDict removeAllObjects];
     89 }
     90 
     91 
     92 #pragma mark - Table view data source
     93 
     94 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
     95     
     96     return 1;
     97 }
     98 
     99 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    100 
    101     return self.appsArray.count;
    102 }
    103 
    104 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    105     static NSString *cellID = @"cellID";
    106     
    107     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    108     
    109     if (!cell) {
    110         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
    111     }
    112     //取出模型
    113     BWApp *app = [self.appsArray objectAtIndex:indexPath.row];
    114     
    115     cell.textLabel.text = app.name;
    116     cell.detailTextLabel.text = app.download;
    117     
    118     //先从imageDict缓存中取出图片url对应的image
    119     UIImage *image = self.imageDict[app.icon];
    120     
    121     if (image) { //说明图片已经下载成功过
    122         cell.imageView.image = image;
    123     }
    124     else //说明图片未下载(没有缓存)
    125     {
    126         //获取caches路径,拼接文件路径
    127         NSString *filePath = appImageCachesPath(app.icon);
    128         
    129         NSData *data = [NSData dataWithContentsOfFile:filePath];
    130         
    131         if (data) { //沙盒中存在这个图片
    132             cell.imageView.image = [UIImage imageWithData:data];
    133         }
    134         else{
    135             //显示占位图片
    136             cell.imageView.image = [UIImage imageNamed:@"placeholder"];
    137         }
    138         
    139         [self download:app.icon andIndexPath:indexPath];
    140     }
    141     return cell;
    142 }
    143 
    144 - (void)download:(NSString *)imageUrl andIndexPath:(NSIndexPath *)indexPath
    145 {
    146     //取出当前图片对应的下载操作(operation对象)
    147     BWDownloadOperation *operation = self.operationDict[imageUrl];
    148     
    149     if (operation)  return;
    150 
    151     //创建操作下载图片
    152     operation = [[BWDownloadOperation alloc] init];
    153     operation.imageUrl = imageUrl;
    154     operation.indexPath = indexPath;
    155     
    156     //设置代理
    157     operation.delegate = self;
    158     
    159     //添加操作到队列中
    160     [self.queue addOperation:operation];
    161     
    162     //添加操作到字典中(为了解决重复下载)
    163     self.operationDict[imageUrl] = operation;
    164 
    165 }
    166 
    167 #pragma mark - 下载代理方法
    168 
    169 - (void)downloadOperation:(BWDownloadOperation *)operation didFinishDownload:(UIImage *)image
    170 {
    171 
    172     
    173     //UIImageJPEGRepresentation(<#UIImage * _Nonnull image#>, <#CGFloat compressionQuality#>)
    174     
    175     //判断图片是否存在
    176     if (image) {
    177         //存放图片到字典中
    178         self.imageDict[operation.imageUrl] = image;
    179         
    180 #warning 沙盒缓存
    181         //将图片存入沙盒之中 UIImage --> NSData --> File(文件)
    182         NSData *data = UIImagePNGRepresentation(image);
    183         
    184         //写入缓存
    185         [data writeToFile:appImageCachesPath(operation.imageUrl) atomically:YES];
    186 
    187     }
    188     //从字典中移除下载操作(防止operationDict的下载操作越来越大,保证下载失败后能重新下载)
    189     [self.operationDict removeObjectForKey:operation.imageUrl];
    190     //刷新表格
    191     //[self.tableView reloadData];
    192     [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone];
    193 }
    194 
    195 
    196 //保证图片只下载过一次
    197 //当用户开始拖拽表格时
    198 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    199 {
    200     //暂停下载
    201     [self.queue setSuspended:YES];
    202 }
    203 //用户停止拖拽表格时
    204 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    205 {
    206     //恢复下载
    207     [self.queue setSuspended:NO];
    208 }
    209 
    210 
    211 @end

    四、SDWebImage

     1 //
     2 //  BWApp.h
     3 //  IOS_0120_NSOperation防止重复下载
     4 //
     5 //  Created by ma c on 16/1/20.
     6 //  Copyright © 2016年 博文科技. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 
    11 @interface BWApp : NSObject
    12 
    13 @property (nonatomic, copy) NSString *name;
    14 @property (nonatomic, copy) NSString *download;
    15 @property (nonatomic, copy) NSString *icon;
    16 
    17 + (instancetype)appWithDict:(NSDictionary *)dict;
    18 
    19 @end
    20 
    21 
    22 //
    23 //  BWApp.m
    24 //  IOS_0120_NSOperation防止重复下载
    25 //
    26 //  Created by ma c on 16/1/20.
    27 //  Copyright © 2016年 博文科技. All rights reserved.
    28 //
    29 
    30 #import "BWApp.h"
    31 
    32 @implementation BWApp
    33 
    34 + (instancetype)appWithDict:(NSDictionary *)dict
    35 {
    36     BWApp *app = [[self alloc] init];
    37     [app setValuesForKeysWithDictionary:dict];
    38     return app;
    39 }
    40 
    41 @end
      1 //
      2 //  BWTableViewController.m
      3 //  IOS_0120_NSOperation防止重复下载
      4 //
      5 //  Created by ma c on 16/1/20.
      6 //  Copyright © 2016年 博文科技. All rights reserved.
      7 //
      8 
      9 #import "BWTableViewController.h"
     10 #import "BWApp.h"
     11 #import "UIImageView+WebCache.h"
     12 
     13 @interface BWTableViewController ()
     14 
     15 //所有应用数据
     16 @property (nonatomic, strong) NSMutableArray *appsArray;
     17 
     18 @end
     19 
     20 @implementation BWTableViewController
     21 
     22 #pragma mark - 懒加载
     23 - (NSMutableArray *)appsArray
     24 {
     25     if (!_appsArray) {
     26         NSMutableArray *appArr = [[NSMutableArray alloc] init];
     27         
     28         NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];
     29         
     30         NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
     31         
     32         for (NSDictionary *dict in dictArr) {
     33             
     34             BWApp *app = [BWApp appWithDict:dict];
     35             [appArr addObject:app];
     36         }
     37         _appsArray = appArr;
     38     }
     39     return _appsArray;
     40 }
     41 
     42 #pragma mark - 初始化
     43 - (void)viewDidLoad {
     44     [super viewDidLoad];
     45     
     46 }
     47 
     48 - (void)didReceiveMemoryWarning
     49 {
     50     [super didReceiveMemoryWarning];
     51 }
     52 
     53 #pragma mark - Table view data source
     54 
     55 //- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
     56 //    
     57 //    return 1;
     58 //}
     59 
     60 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     61 
     62 //    return self.appsArray.count;
     63     return 1;
     64 }
     65 
     66 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     67     
     68     static NSString *cellID = @"cellID";
     69     
     70     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
     71     
     72     if (!cell) {
     73         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
     74     }
     75     //取出模型
     76     BWApp *app = [self.appsArray objectAtIndex:indexPath.row];
     77     //设置基本信息
     78     cell.textLabel.text = app.name;
     79     cell.detailTextLabel.text = app.download;
     80     
     81     //下载图片
     82 //    NSURL *url = [NSURL URLWithString:@"http://img.cnblogs.com/ad/not-to-stop-questioning.jpg"];
     83     
     84     NSURL *url = [NSURL URLWithString:app.icon];
     85     UIImage *image = [UIImage imageNamed:@"placeholder"];
     86 //    [cell.imageView sd_setImageWithURL:url placeholderImage:image];
     87     
     88     SDWebImageOptions options = SDWebImageRetryFailed | SDWebImageLowPriority;
     89     
     90     [cell.imageView sd_setImageWithURL:url placeholderImage:image options:options progress:^(NSInteger receivedSize, NSInteger expectedSize) {
     91         
     92         NSLog(@"下载进度:%f",(double)receivedSize / expectedSize);
     93         
     94     } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
     95         NSLog(@"-----图片加载完毕-----%@",image);
     96     }];
     97     
     98     return cell;
     99 }
    100 
    101 @end
    1 - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
    2 {
    3     SDWebImageManager *maneger = [SDWebImageManager sharedManager];
    4     //1.取消正在下载的操作
    5     [maneger cancelAll];
    6     //2.清除内存缓存
    7     [maneger.imageCache clearMemory];
    8     maneger.imageCache.maxCacheAge = 100*24*60*60;
    9 }
  • 相关阅读:
    linux poll 和 select
    linux测试 scullpipe 驱动
    linux进程唤醒的细节
    linux进程互斥等待
    linux 手动睡眠
    linux一个进程如何睡眠
    [POJ 2431]Expedition
    【MongoDB数据库】MongoDB 命令入门初探
    高速排序为什么快?
    [050] 微信公众平台开发入门视频教程已公布
  • 原文地址:https://www.cnblogs.com/oc-bowen/p/5144991.html
Copyright © 2011-2022 走看看