所以我被这个问题难住了,不知道最好的方法是什么。我需要从api下载,存储在core data,然后显示一组单元格的tableview只有一个标题,描述和图片(图片是一个url,所以我需要下载)。tableview只有一个section
我已经在我的TableViewController中设置了一个结构,我正在制作self。tableview是一个NSNotification的监听器(在init中指定)。我已经创建了一个自定义单元格视图,具有一个名为firstLoad的额外属性,在初始化期间被设置为YES。在我的tableView cellForRowAtIndexPath中,我检查firstload属性,如果它设为yes,我调用一个函数从url下载图像。当这种情况发生时,发出通知,由tableviewcontroller中的函数捕获,我得到indexpathsforvisiblerows如果来自通知的行与来自indexpathsforvisiblerows数组之一的行匹配,我设置单元格的图像,然后reloadData
我遇到的问题是,当我开始滚动tableview,它看起来有时图像设置为错误的单元格。这些细胞也被重新利用。
我不知道该如何处理这个问题。非常感谢你的帮助!!
这是cellForRowAtIndexPath的代码
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"APCell";
APTableViewGenCell *cell = (APTableViewGenCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[APTableViewGenCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier useType:_useType] autorelease];
}
// Configure the cell...
if (APUseTypeGroupsWithEvents == _useType) {
APGroup *group = [_fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = group.name;
UIImage *logoImage = [UIImage imageNamed:@"groups.png"];
if (group.logo.imageURL && (cell.firstLoad == (BOOL *)YES)){
cell.imageView.image = [logoImage scaleToSize:CGSizeMake(kTableImageWidth, kTableImageHeight)];
APGroundControl *gc = [APGroundControl sharedGroundControl];
[gc retrieveImageWithURL:group.logo.imageURL indexPath:indexPath withDefaultImgName:@"groups" andDefaultImgType:@"png" sender:self];
}
cell.detailTextLabel.text = group.groupDescription;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
这是收到的通知处理程序:
- (void)imageRetrieved:(NSNotification *)notification {
NSLog(@"%@", @"NOTIFICATION RECEIVED");
if ([[[notification userInfo] objectForKey:kNewImageDownloadedSenderKey] isEqual:self]) {
// If the cell is still visible show the image.
NSIndexPath *indexPath = [[notification userInfo] objectForKey:kNewImageDownloadedIndexPathKey];
if (indexPath) {
NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
for (NSIndexPath *path in indexPaths) {
if (indexPath.row == path.row) {
APTableViewGenCell *cell = (APTableViewGenCell *)[self.tableView cellForRowAtIndexPath:path];
NSData *imageData = [[notification userInfo] objectForKey:kNewImageDownloadedDataKey];
UIImage *logoImage = nil;
cell.firstLoad = (BOOL *)NO;
if ([imageData isKindOfClass:[UIImage class]]) {
logoImage = (UIImage *)imageData;
logoImage = [logoImage scaleToSize:CGSizeMake(kTableImageWidth, kTableImageHeight)];
cell.imageView.image = logoImage; // @todo: get rid of this temp check once all image gets moved over to the new retrieve function
}
else {
logoImage = [UIImage imageWithData:imageData];
logoImage = [logoImage scaleToSize:CGSizeMake(kTableImageWidth, kTableImageHeight)];
cell.imageView.image = logoImage;//[UIImage imageWithData:imageData];
}
break;
}
}
[self.tableView reloadData];
}
}
}
和retrieveImageWithUrl:
的代码- (void)retrieveImageWithURL:(NSString *)url indexPath:(NSIndexPath *)indexPathOrNil withDefaultImgName:(NSString *)defaultImgName andDefaultImgType:(NSString *) defaultImgType sender:(id)sender {
NSLog(@"%@", @"RETRIEVE IMAGE CALLED");
NSLog(@"%@", indexPathOrNil);
[self queueBlock:^{
NSData *imageData = nil;
// Get image locally
if ([url isEqualToString:kGetGroupDefaultLogoURL]){
NSString *filePath = [[NSBundle mainBundle] pathForResource:defaultImgName ofType:defaultImgType];
imageData = [NSData dataWithContentsOfFile:filePath];
}
// @todo: add a default user logo
else if (url == nil) {
NSLog(@"%@", @"Default Retrieve");
NSString *filePath = [[NSBundle mainBundle] pathForResource:defaultImgName ofType:defaultImgType];
imageData = [NSData dataWithContentsOfFile:filePath];
}
else {
NSLog(@"%@", @"Local Retrieve");
imageData = [_imageCache objectForKey:url];
}
// If local image does not exist get it from the internet
if (imageData == nil) {
NSLog(@"%@", @"Remote Retrieve");
NSLog(@"URL = %@", url);
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
if (imageData == nil) {
NSString *filePath = [[NSBundle mainBundle] pathForResource:defaultImgName ofType:defaultImgType];
imageData = [NSData dataWithContentsOfFile:filePath];
}
[_imageCache setObject:imageData forKey:url];
}
// Send out notification
NSMutableArray *objects = [NSMutableArray array];
NSMutableArray *keys = [NSMutableArray array];
if (indexPathOrNil) {
[objects addObject:indexPathOrNil];
[keys addObject:kNewImageDownloadedIndexPathKey];
}
[objects addObject:sender];
[keys addObject:kNewImageDownloadedSenderKey];
[objects addObject:imageData];
[keys addObject:kNewImageDownloadedDataKey];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@", @"NOTIFICATION SENT");
[[NSNotificationCenter defaultCenter] postNotificationName:kNewImageDownloadedNotification object:self userInfo:userInfo];
});
}];
}
好的,首先,您使用的firstLoad
-标志没有意义。您需要知道您的图像是否已经加载,但由于可重用的单元格不能与特定的图像连接,因此这不是这样做的。
你更新了你的帖子几次,到现在为止,它不是很清楚你目前的问题是什么。因此,我将为您提供一种适当而干净的解决方案:首先,您需要一个地方来存储您的图像。一个NSMutableDictionary
就可以了。使用键来存储url,使用值来存储图像。当您输入一个新的单元格时,查看URL是否已经在字典中。如果有,填上即可。否则,启动加载进程。如果这样做,还应该在字典中创建一个新条目,该条目存储图像的URL和nil
。这可以帮助您避免两次加载尚未准备好的图像。在"Loading complete"方法中,您将nil
值替换为您的映像。应该就是这个了。当然,您需要根据自己的具体需求定制这些步骤,但这应该不是什么大问题。希望这对你有帮助!
PS:另外,您应该检查代码以查找冗余或过于复杂的调用。在不知道具体设置的情况下,迭代NSIndexPath
看起来很奇怪,您应该能够直接访问您的值。
可能是从表视图中取出的单元格保留了它们之前的图像。尝试在cellForRowAtIndexPath中将imageview图像设置为nil(在将其更新为新图像之前,这可能需要一些时间)。