我有一个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
有没有其他人遇到过这样的问题,或者能否发现我的代码存在问题?谢谢!
答案 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];
答案 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的样本中起作用而不强制主线程。
有什么想法吗?