Iphone 为什么不';是否在滚动之前加载UItableViewCell图像?

Iphone 为什么不';是否在滚动之前加载UItableViewCell图像?,iphone,objective-c,uitableview,nsurlconnection,Iphone,Objective C,Uitableview,Nsurlconnection,我的代码使用tableview:cellforrowatinexpath:方法异步下载图像,方法是使用initWithURL初始化IntentImage并调用downloadImage。此代码在向下滚动到UITableView中的新单元格UITableViewCell后运行良好,但不是在之前,即使URL在这两种情况下都是正确的。InternetImage的NSURLConnection委托方法都不会被调用来通知我连接的成功或失败,因为它们应该是这样的。调用reloadData:、setNeeds

我的代码使用
tableview:cellforrowatinexpath:
方法异步下载图像,方法是使用initWithURL初始化IntentImage并调用downloadImage。此代码在向下滚动到UITableView中的新单元格UITableViewCell后运行良好,但不是在之前,即使URL在这两种情况下都是正确的。InternetImage的NSURLConnection委托方法都不会被调用来通知我连接的成功或失败,因为它们应该是这样的。调用
reloadData:
setNeedsDisplay:
、和
setNeedsLayout:
时,由于映像无法下载,因此不执行任何操作

-(void) internetImageReady:(InternetImage*)downloadedImage
{   
    // The image has been downloaded. Put the image into the UIImageView
    [imageView setImage:downloadedImage.Image];
}
以下是我的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;
    }

如果您询问为什么加载表后图像不会在后台下载,这是因为
tableView:cellforrowatinexpath:
仅在屏幕单元格的
indexpath
中调用

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


然后在UITableView委托中实现
tableView:willDisplayCell:forrowatinexpath:
,并让它负责将正确的
InternetImage
对象分配给每个单元格的
imageView
属性。

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

InternetImage
中,我注意到有这个函数。 您需要做的是让此函数通知您的
TableView
进行“刷新”。您可以通过向稍后调用的类传递委托函数来实现这一点,但现在事情变得非常棘手。因为当您离开视图时,您需要为您尝试下载的每个图像将委托函数设置为“nil”

-(void) internetImageReady:(InternetImage*)downloadedImage
{   
    // The image has been downloaded. Put the image into the UIImageView
    [imageView setImage:downloadedImage.Image];
}
当你得到答案后,一定要把答案贴在这里,我很想看看这是否解决了问题。

好的,很好的方法? 首先要检查您在哪里分配imageview? 第二,如果你的图像是固定的,这意味着特定于整个代码

if(cell == nil)
{

}
在那种情况下。我面临着同样的问题,并像这样解决了。
让我知道这是否有效。

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

该方法需要进行以下更改:

  • 推卸责任 将图像下载到对象
  • 修改对象以发送事件/调用委托/在图像更改时通知属性已更改
  • 子类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;
}

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


不过,如果它至少能在缓慢滚动时工作,并且在快速滚动时仅阻止下载,那就太好了。

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

此外,从您的描述中还不完全清楚滚动时会发生什么。很明显,后续的呼叫是有效的,但是之前尝试的所有连接是突然在该点启动,还是完全丢失

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

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

  • InternetImage似乎做了很多习惯用法上与通用Cocoa编程约定不一致的事情。至少对我来说,这使得快速阅读变得更加困难,而且我不完全确定它是否做得正确
  • 不要使用_imageScaledToSize:。这是苹果的私人方法,如果他们注意到你正在使用它,可能会导致拒绝

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

    我使用的是马克·约翰逊课程的一个稍加修改的版本。对图像的异步请求不会导致调用任何委托,直到我滚动tableview。当我将一个单元格从视图中滚动出来并返回时,调用会再次启动并正确获取数据

    我在别处读到,NSURLConnection取决于运行循环是否处于某个特定的状态