在UITableView滚动之前,NSURLConnection不会“触发”

时间:2010-06-09 06:20:00

标签: iphone objective-c uitableview nsurlrequest

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

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

这是我的代码:


HomeController.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];   
        }
    }

IconDownload.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

有没有其他人遇到过这样的问题,或者能否发现我的代码存在问题?谢谢!

5 个答案:

答案 0 :(得分:1)

您可以使用此代码

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

而不是

[tableView reloadData];

答案 1 :(得分: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

答案 2 :(得分:0)

你没有开始NSURLConnection。可以使用-[NSURLConnection initWithRequest:delegate:startImmediately:]对其进行初始化,也可以在初始化后手动调用-[NSURLConnection start]

答案 3 :(得分:0)

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

编辑:是的,对我有用。让我知道是否也适合您,或者您需要更多信息。

答案 4 :(得分:0)

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

虽然Apple测试项目中的代码有效,但它在我的项目中无效 - 尽管我只是复制了Apple的代码。

我发现的是:当我使用

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

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

这可能是问题所在。

知道如何解决?


编辑!!!解决了!

我刚使用

强制使用主线程
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的样本中起作用而不强制主线程。

有什么想法吗?