【问题标题】:Delayed UIImageView Rendering in UITableViewUITableView 中的延迟 UIImageView 渲染
【发布时间】:2010-12-22 01:34:24
【问题描述】:

好的,我有一个带有自定义UITableViewCells 的UITableView,每个都包含一个UIImageView,其图像通过NSURLConnection 异步下载。所有非常标准的东西......

问题是,当表格滚动时,新图像会在后台正确下载,但在表格停止移动之前不会渲染。

如何让表格即使在移动时也能呈现其内容? 谢谢。

-- 更新--

仔细观察后,我发现NSURLConnection 委托方法在表格停止滚动之前不会触发。不知道为什么。任何帮助都会很棒。

【问题讨论】:

    标签: iphone uiimageview uitableview nsurlconnection


    【解决方案1】:

    您应该阅读 NSRunLoop。我怀疑,在滚动期间,运行循环在 NSEventTrackingRunLoopMode 中运行,并且 NSURLConnection 不包含在该模式中。你可以通过调用 NSURLConnection 的 scheduleInRunLoop:forMode: 来解决这个问题,这样下载就可以在滚动期间进行。

    这可能会影响滚动性能,这可能首先是单独运行循环模式的原因。但是尝试一下,看看感觉如何!

    【讨论】:

      【解决方案2】:

      首先...您的连接可能在到达 mainRunLoop 之前甚至还没有开始,这也是滚动动画正在处理的地方。

      我遇到了同样的问题,并通过告诉图像的连接在创建后立即启动来解决它。

          NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:wrapper.request delegate:wrapper];
      
          [connection start];
      

      在您接收图像并将 cell.imageView.image 设置为接收到的图像的完成例程中,您应该检查该单元格是否属于当前显示在表格中的单元格之一...如果所以调用 [tableView reloadData]。

          NSInteger itemIndex = theIndexInTheRowDataOfTheCellYouStuffedTheImage
      
          NSArray *indicies = [_tableView indexPathsForVisibleRows];
          NSUInteger rows = indicies.count;
      
          if (rows > 0 &&
              itemIndex >= ((NSIndexPath *)[indicies objectAtIndex:0]).row &&
              itemIndex <= ((NSIndexPath *)[indicies objectAtIndex:rows - 1]).row)
          {       
              [_tableView reloadData];
          }
      

      【讨论】:

        【解决方案3】:

        如果您将图像下载和更新包装在 NSOperation 中,则更新将随着表格视图的滚动而发生。

        NSOperation 的另一个好处是,您可以在单元格滑出屏幕时取消操作。它会感觉对用户反应更快。尤其是当他们快速滚动长列表时。今年的 Apple 技术讲座鼓励了这种技术。

        如果您的列表不是那么长,或者您希望它们继续加载,则可以改为操纵 NSOperation 优先级。

        【讨论】:

        • 我最初是这样设计我的代码的,它很棒。然后我迁移到使用 NSURLConnection 的 Three20 并遇到了 Brad 描述的完全相同的问题。我将尝试下面的启动和运行循环建议。
        【解决方案4】:

        在您停止滚动之前不会触发连接委托消息的原因是因为在滚动期间,运行循环位于 UITrackingRunLoopMode 中。默认情况下,NSURLConnection 仅在NSDefaultRunLoopMode 中进行调度,因此您在滚动时不会收到任何消息。

        以下是在“普通”模式下安排连接的方法,其中包括UITrackingRunLoopMode

        NSURLRequest *request = ...
        NSURLConnection *connection = [[NSURLConnection alloc]
                                       initWithRequest:request
                                       delegate:self
                                       startImmediately:NO];
        [connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
                    forMode:NSRunLoopCommonModes];
        [connection start];
        

        请注意,您必须在初始化程序中指定 startImmediately:NO,这似乎与 Apple 的文档背道而驰,该文档建议您即使在运行循环模式启动后也可以更改它。

        【讨论】:

        • 效果很好。感谢分享,顺便问一下这个有什么副作用吗?
        • 嗯,丹尼尔你是我的英雄。我一直在寻找答案。你救了我的命!
        • 工作就像一个魅力,但很难理解为什么。目前只能激活一个 runloop 吗?
        • 每个线程都可以有一个运行循环,但通常只有主线程有一个运行循环,这就是这里的相关内容。操作系统可能在滚动期间以不同的模式运行,以防止运行循环调度的事件导致 UI 卡顿。这在 2010 年比现在更重要,即使在 iOS 设备中,多核 CPU 也是常态——现在我建议在后台线程上执行网络请求等(例如使用dispatch_async,然后回调到 UI 的主线程中)绘图)。
        猜你喜欢
        • 1970-01-01
        • 2011-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-10
        • 2019-01-10
        • 2023-03-15
        • 1970-01-01
        相关资源
        最近更新 更多