为什么UItableViewCell图像加载直到滚动?

时间:2009-08-08 05:13:43

标签: iphone objective-c uitableview nsurlconnection

我的代码使用tableview: cellForRowAtIndexPath:方法中的InternetImage异步下载图像,方法是使用initWithURL初始化IntentImage并调用downloadImage。在UITableView中向下滚动到新单元格UITableViewCell之后,此代码运行完美,但之前没有,即使URL在两种情况下都是正确的。调用InternetImage的NSURLConnection委托方法都不会通知我连接成功或失败的原因。由于图片无法下载,因此调用reloadData:setNeedsDisplay:setNeedsLayout:不会执行任何操作。

以下是我的UiTableViewController子类的代码:

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        Object *object = (Object *)[self.array objectAtIndex:indexPath.row];

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"] autorelease];
        }

        cell.textLabel.text = object.attribute;

        if (object.image == nil && object != nil) {
            NSString *URLString = [[MyAppDelegate imageURLFromLink:(object.link) withExtension:@".jpg"]absoluteString];

            InternetImage *asynchImage = [[InternetImage alloc] initWithUrl:URLString object:object];
            [asynchImage downloadImage:self];
        }

        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

        if (object.image != nil && object.thumbnailImage == nil) {

            UIImage *image= (UIImage *) object.image;
            UIImage *thumbnail = [image _imageScaledToSize:CGSizeMake(75.0, 50.0) interpolationQuality:20];
            object.thumbnailImage = thumbnail;
        }
        cell.imageView.image = object.thumbnailImage;

        return cell;
    }

7 个答案:

答案 0 :(得分:2)

对我有用的解决方案是将下载的责任转移到Object,并将处理图像刷新的责任转移到表格单元本身。如果对象在屏幕上可见并且具有相应的表格单元格,则图像将在下载后立即刷新。

这种方法需要进行以下更改:

  • 移除责任 将图像下载到对象。
  • 修改对象以发送事件/调用委托/通知图像更改时属性已更改。
  • 子类UITableViewCell,用于了解它将显示的对象,该对象在分配时将自身添加为对象的更改委托。

这是一个如何运作的草图:

// in the UITableViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  Object *object = (Object *)[self.array objectAtIndex:indexPath.row];

  ObjectTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"objectcell"];
  if (nil == cell) {
    cell = [[[ObjectTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"objectcell"] autorelease];
  }

  cell.object = object;

  return cell;
}

// in Object

- (void) downloadImageIfNeeded {
  if (nil == image && nil == internetImage) {
     NSString *URLString = [[MyAppDelegate imageURLFromLink:(object.link) withExtension:@".jpg"]absoluteString];

     internetImage = [[InternetImage alloc] initWithUrl:URLString object:object];
     [internetImage downloadImage:self];
  }
} 

- (void) internetImageReady:(InternetImage*)downloadedImage {
  self.image = downloadedImage.image;
  self.thumbnailImage = [image _imageScaledToSize:CGSizeMake(75.0, 50.0) interpolationQuality:20];

  // notify the delegate
  [imageDelegate imageChanged: self];
}

// in ObjectTableViewCell.h
@property (nonatomic, retain) Object *object;

// in ObjectTableViewCell.m
- (Object *) object {
  return object;
}

- (void) setObject: (Object *) obj {
  if (obj != object) {
    object.imageDelegate = nil;
    [object release];
    object = nil;

    if (nil != object) {
      object = [obj retain];
      object.imageDelegate = self;

      [object downloadImageIfNeeded];
      self.textLabel.text = object.attribute;
      self.imageView.image = object.thumbnailImage;

      self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
   }
}

- (void) imageChanged: (Object *) o {
  self.imageView.image = object.thumbnailImage;
}

答案 1 :(得分:1)

如果你问为什么你的图片在加载表后没有在后台下载,那是因为只有tableView:cellForRowAtIndexPath:屏幕上的单元格调用了indexPaths

如果您希望一次下载所有图像而不是单元格在屏幕上滚动,请编写一个循环遍历array属性并在其中实例化InternetImage个对象的方法。可能的地方可能是viewDidLoad

然后在UITableView委托中实现tableView:willDisplayCell:forRowAtIndexPath:,并使其负责为每个单元格的InternetImage属性分配正确的imageView对象。

答案 2 :(得分:1)

只要表格滚动,NSUrlConnections确实似乎不会检索数据。滚动停止后,它会立即继续检索数据。然而,在任何iPhone应用程序中都可以看到此行为(只要表格滚动,图像就不会加载),最后,我决定在我的应用程序中使用它。我认为,Apple是故意这样做的。如果用户滚动速度非常快,可能会阻止设备使用大量图像请求来敲击服务器;或者甚至可以随时为用户保持平滑滚动。

然而,如果它在缓慢滚动时至少工作并且在快速滚动时仅阻止下载,那将是很好的。

答案 3 :(得分:0)

我实际上花了一些时间查看代码。

InternetImage我注意到有这个功能。 你要做的就是让这个功能通知你TableView“刷新”。您可以通过将委托函数传递给稍后调用的类来完成此操作,但现在事情变得非常棘手。因为当您离开视图时,您需要为您要下载的每个图像将委托功能设置为“nil”。

-(void) internetImageReady:(InternetImage*)downloadedImage
{   
    // The image has been downloaded. Put the image into the UIImageView
    [imageView setImage:downloadedImage.Image];
}

当你得到它时,请在这里发布答案,我很想知道这是否解决了。

答案 4 :(得分:0)

好的方法? 首先检查你分配imageview的位置? 如果您的图像是固定的,那么第二个意味着特定于

中的整个代码
if(cell == nil)
{

}
那边条件。我遇到了同样的问题并且像这样解决了。 让我知道这是否有效。

答案 5 :(得分:0)

好的,首先,你在这里发布的不是你正在使用的,或者你已经修改了你没有提到的InternetImage,因为InternetImage没有响应initWithUrl:object:。您还没有将代码包含在委托方法internetImageReady中。我知道当出现问题时它不会被调用,但是一旦你开始滚动就会调用它,并且在正确的情况下进行对比会有助于人们诊断你的问题。

此外,从您的描述中不完全清楚滚动时会发生什么。显然,后续调用可以正常工作,但是之前尝试的所有连接是否突然从那一点开始,或者它们是否完全丢失了?

至于发生了什么,出于上述原因我不相信任何人可以做的不仅仅是给你一些猜测。如果我不得不下注,如果我在上一段中所说的话正在发生,那么你的问题是(无论出于何种原因)主线程runloop不会处理NSURLConnections事件,直到某些事情发生在泵上。这可能有很多原因,例如runloop处于错误模式。您可以尝试手动运行NSRunLoop,或者更改为InternetImage以显式设置runloop,或手动启动下载。

两个快速旁白

  1. InternetImage似乎做了许多与一般Cocoa编程约定惯用不一致的事情。至少对我而言,这使我更难以快速阅读,而且我并不完全确定它是在正确地做事。
  2. 不要使用_imageScaledToSize:。这是一种私有的Apple方法,如果他们发现您正在使用它,可能会导致拒绝。

答案 6 :(得分:0)

我没有答案,但我可以告诉你我遇到了同样的问题。

我正在使用Mark Johnson AsyncImageView课程的略微修改版本。在滚动tableview之前,对图像的异步请求不会导致调用任何委托。只要我将一个单元格滚出视图并返回,该调用就会再次触发并正确获取数据。

我在别处读到NSURLConnection依赖于运行循环处于某种模式 - 我不知道在tableView:cellForIndexPath中启动URLConnection请求的情况下是否有数字。

如何调试NSURLConnection内部结构?

[UPDATE]

好的,所以我通过明确地在主线程上启动连接来解决我的这个问题的特定实例。我将连接设置代码放在不同的选择器中,并通过performSelectorOnMainThread调用它,一切都很好。

您应该尝试在启动连接的选择器中记录当前的runloop模式 - 我发现这不是NSUrlConnection需要的默认runloop模式。