NSOperation综合案例: 下载图片/技术选择

/*---------------------------  NSOperation综合案例: 下载图片/技术选择  ----------------------------*/
重点: 1.分析项目需求; 2.处理内存警告,优化用户体验; 3.技术选择,技术点实施,代码编写. 4.Bug?
{
    项目需求:
    <1> 下载图片;
    分析:
        1>.子线程下载图片,主线程显示图片.
        2>.开启子线程有三种技术方案可供选择: (1)NSThread ,(2)GCD ,(3)NSOperation 配合 NSOperationQueue使用.
    
    <2> 内存警告处理;
    分析:
        接收到内存警告的时候,停止一切下载操作,防止闪退.
    
    <3> 用户体验;
    分析:
        在与用户做 UI 交互的时候,最好暂停图片的下载;用户滚动结束之后,再继续下载图片.
    
    1. 技术选择 : (3)NSOperation 配合 NSOperationQueue使用.
    2. 技术点实施:
    // <1>用户开始滚动的时候,暂停下载操作;停止滚动之后,恢复下载操作.
    {
#pragma UIScrollViewDelegate
        // 开始滚动的时候调用
        - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
        {
            NSLog(@"暂停下载---");
            // 暂停所有下载操作
            [self.queue setSuspended:YES];
        }
        // 滚动结束的时候调用
        - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
        {
            NSLog(@"恢复下载---");
            // 恢复所有下载操作
            [self.queue setSuspended:NO];
        }

    }
    // <2>接收到内存警告的时候,取消一切操作.
    {
        // 接收到内存警告的时候调用
        -(void)didReceiveMemoryWarning
        {
            [super didReceiveMemoryWarning];
            // 取消一切下载操作
            [self.queue cancelAllOperations];
            
        }
    }
    // <3>将下载图片的操作封装在 NSBlockOperation.最后将操作放在并发队列中.自动执行!
    {
        __weak typeof(self) wself = self;
        // 定义下载操作
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
            // 下载网络图片
            UIImage *webImage = [wself downloadWebImage:app.icon];
            //回到主线程显示图片
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                // 显示图片
                cell.imageView.image = webImage;
            }];
        }];
        
        // 将下载操作放在并发队列中.自动开启下载.
        [self.queue addOperation:op];

    }
    
    3.运行程序之后,发现 3 个Bug:
    <1> 程序运行之后,图片不会直接显示出来.需要刷新之后才能显示(滚动/点击都会重绘 UI).
    <2> 图片错位问题.
    <3> 用户体验方面的Bug:只要滚动,图片就会重复下载.即使已经下载好的图片,也会重新下载.(耗费流量,体验巨差,巨耗电).

}

发现 3 个Bug解决方案:

 1.分析Bug产生的原因并解决Bug. 2.如何防止一个url对应的图片重复下载?
{
    Bug 产生的原因分析:
    
    <1> "程序运行之后,图片不会直接显示出来.需要刷新之后才能显示(滚动/点击都会重绘 UI)."
    
        Bug产生原因: UITableViewCell 中刚开始没有设置图片的 Frame,图片下载完后,点击/刷新之后,就会重新绘制 UITableViewCell,这样就会显示图片了.
    
        解决 Bug :下载之前最好先把图片的 Frame 绘制出来.比如,可以添加一张占位图片.
    {
        // 设置占位图片.
        cell.imageView.image = [UIImage imageNamed:@"placeholder"];
    }
    
    <2> "图片错位问题."
    
        Bug产生原因: UITableViewCell 的重用以及网络下载延时产生的.
    
        解决 Bug :让数据控制视图(视图根据数据来显示),设置一个图片缓存,cell 中的图片来源于这个图片缓存.
    {
        <1>.设置图片缓存.
        定义一个字典做为图片缓存,保存下载好的图片(以图片的 url 作为 key 值;以下载好的图片为 Value).
        // 可以选择 NSCache 代替字典作为缓存机制.
        // NSCache在内存紧张的时候,会自动释放一些资源(自动销毁图片,我们无法控制).
        // 如果使用字典,在接收到内存警告之后,需要手动释放资源.
        
        <2>.从缓存中取出 cell 对应的图片.
        cell 设置图片:根据 cell 的 从字典中取出对应的图片.
        
        <3>.图片下载完毕之后刷新所在行的数据.
        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        
        注意: 没必要刷新整个表格视图,刷新所在行的数据就可以了.
    }
    
    <3> "用户体验方面的Bug:只要滚动,图片就会重复下载.即使已经下载好的图片,也会重新下载.(耗费流量,体验巨差,巨耗电)."
    
        Bug产生原因: 只要上下滚动,就会调用 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 这个方法.这个方法频繁调用导致下载操作一直创建.
    
        解决 Bug :每次创建下载操作之前,最好先检查一下载操作是否存在,对于已经存在的操作,不要重复下载.
    {
        <1>.设置操作缓存.
        定义一个字典作为下载操作缓存,保存已经创建好的下载操作(同样,以图片的 url 为 key值;以操作Operation为 Value).
        
        <2>.从缓存中取出操作比较.
        每次重新创建下载操作之前,首先从下载操作缓存之中查看操作是否已经存在.如果存在,就不要再次创建;如果不存在,创建新的下载操作.
        
        <3>.防止操作缓存越来越大
        图片下载成功之后,就下载操作就没有存在的意义了,应该及时清除缓存,防止下载操作缓存越来越大.
        
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值