2

我有一个 UITableView,它异步加载图像并在加载后将其放置在 UITableViewCell 中(我使用的代码与“LazyTableImages”教程中的代码几乎完全相同)。当我滚动表格时,这适用于所有图像,但它不会加载视图中的第一个图像。

该代码绝对可以正常工作,因为正确调用了实际发送 NSURLConnection 请求的类(我添加了一个 NSLog 并到达了控制台)。NSURLConnection 只是不调用委托方法(didReceiveData、connectionDidFinishLoading 等)。

这是我的代码:


家庭控制器.m

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

 if (cell == nil) {

        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

  NSArray *feed = [feeds objectAtIndex: indexPath.row];

  /**
    * Name of person
   */
  [...]

  /**
    * Feed entry
   */
  [...]

  /**
    * Misc work
   */
  [...]

 }

 FeedRecord *feedRecord = [self.entries objectAtIndex:indexPath.row];

 if( !feedRecord.image ) {

  if (self.table.dragging == NO && self.table.decelerating == NO)
  {
   [self startIconDownload:feedRecord forIndexPath:indexPath];
  }

  cell.imageView.image = [UIImage imageNamed:@"Placeholder.png"];                

 }

    return cell;
 }

    - (void)startIconDownload:(FeedRecord *)feedRecord forIndexPath:(NSIndexPath *)indexPath
    {
        IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath];
        if (iconDownloader == nil) 
        {
            iconDownloader = [[IconDownloader alloc] init];
            iconDownloader.feedRecord = feedRecord;
            iconDownloader.indexPathInTableView = indexPath;
            iconDownloader.delegate = self;
            [imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
            [iconDownloader startDownload];
            [iconDownloader release];   
        }
    }

图标下载.m

#import "IconDownloader.h"
#import "FeedRecord.h"

#define kAppIconHeight 48

@implementation IconDownloader

@synthesize feedRecord;
@synthesize indexPathInTableView;
@synthesize delegate;
@synthesize activeDownload;
@synthesize imageConnection;

#pragma mark

- (void)dealloc
{
    [feedRecord release];
    [indexPathInTableView release];

    [activeDownload release];

    [imageConnection cancel];
    [imageConnection release];

    [super dealloc];
}

- (void)startDownload
{
 NSLog(@"%@ %@",@"Started downloading", feedRecord.profilePicture); // this shows in log
    self.activeDownload = [NSMutableData data];
    // alloc+init and start an NSURLConnection; release on completion/failure
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
                             [NSURLRequest requestWithURL:
                              [NSURL URLWithString:feedRecord.profilePicture]] delegate:self];
    self.imageConnection = conn;
 NSLog(@"%@",conn); // this shows in log
    [conn release];
}

- (void)cancelDownload
{
    [self.imageConnection cancel];
    self.imageConnection = nil;
    self.activeDownload = nil;
}


#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
 NSLog(@"%@ %@",@"Got data for", feedRecord.profilePicture);
    [self.activeDownload appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
 NSLog(@"%@",@"Fail!");
 // Clear the activeDownload property to allow later attempts
    self.activeDownload = nil;

    // Release the connection now that it's finished
    self.imageConnection = nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
  NSLog(@"%@ %@",@"Done", feedRecord.profilePicture);
   // Set appIcon and clear temporary data/image
    UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];

 self.feedRecord.image = image;

    self.activeDownload = nil;

 [image release];

    // Release the connection now that it's finished
    self.imageConnection = nil;

 NSLog(@"%@ %@",@"Our delegate is",delegate);
    // call our delegate and tell it that our icon is ready for display
    [delegate feedImageDidLoad:self.indexPathInTableView];
}

@end

有没有其他人经历过这样的事情或者可以识别我的代码的问题?谢谢!

4

5 回答 5

1

你可以使用这个代码

[tableView performSelector:@selector(reloadData) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];

反而

[tableView reloadData];
于 2011-11-26T09:00:41.497 回答
1

您不会调用您在 startDownload 方法中创建的 NSURLConnection 对象的 start 方法。

一定要这样做:

- (void)startDownload
{
    NSLog(@"%@ %@",@"Started downloading", feedRecord.profilePicture); // this shows in log
    self.activeDownload = [NSMutableData data];
    // alloc+init and start an NSURLConnection; release on completion/failure
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
                            [NSURLRequest requestWithURL:
                            [NSURL URLWithString:feedRecord.profilePicture]] delegate:self];
    self.imageConnection = conn;
    NSLog(@"%@",conn); // this shows in log
    [conn start];
    [conn release];
}

您还可以使用构造函数:initWithRequest:delegate:startImmediately:

此外,如果用户滚动它们正在运行的运行循环,您的下载将被阻止。只需在“常用模式”中注册您的连接:

[conn scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

摘自:how-to-avoid-blocked-downloads-during-scrolling

于 2012-01-28T07:48:26.190 回答
0

看看这里:http ://www.depl0y.com/?p= 345 也许会有所帮助。

编辑:是的,正在为我工​​作。让我知道是否也适合您,或者您需要更多信息。

于 2010-08-24T11:26:12.973 回答
0

您不启动我们的NSURLConnection. 初始化它-[NSURLConnection initWithRequest:delegate:startImmediately:]或在初始化后手动调用-[NSURLConnection start]

于 2010-06-09T09:04:50.163 回答
0

我有同样的问题。此外,我几乎使用与您相同的代码(来自 Apple 示例 LazyTableImages)。

虽然 Apple 测试项目中的代码有效,但它在我的项目中不起作用——尽管我只是复制了 Apple 的代码。

我发现的是:当我使用

NSLog(@"Is%@ main thread", ([NSThread isMainThread] ? @"" : @" NOT"));

在 cellForRowAtIndexPath: 以及 IconDownload.m 的 startDownload: (在两个项目中)中,我发现它是 Apple 示例中的主线程,但不是我代码中的主线程。

这可能是问题所在。

知道如何解决吗?


编辑 !!!解决了 !

我只是强制主线程使用

NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:entry.imageURL, @"imageURL", indexPath, @"indexPath", nil];
[self performSelectorOnMainThread:@selector(startIconDownload:) withObject:info waitUntilDone:NO];

在 cellForRowAtIndexPath 中:您将需要一本字典来向该方法发送多个参数。

您可以在代码中执行类似的解决方案。换行:

[self startIconDownload:feedRecord forIndexPath:indexPath];

使用我的代码并修改 startIconDownload: 像这样

- (void)startIconDownload:(NSDictionary *)info
{
    NSString *url = [info objectForKey:@"imageURL"];
    NSIndexPath *indexPath = [info objectForKey:@"indexPath"];
    ...
}

您的应用程序中的某些变量可能会有所不同。

但我只是不明白为什么它在不强制主线程的情况下在 Apple 的示例中工作。

任何想法?

于 2011-02-04T19:08:56.490 回答