iPhone的UITableView,细胞和通知 - 通知

问题描述:

后的细胞无法显示正确的图像所以我难倒就这个问题和不知道该怎么办的最好方式,这是。我需要从api下载,存储核心数据,然后显示一组tableview的单元格,只有一个标题,描述和图片(图片是一个url,所以我也需要下载)。该tableview中只有一个部分iPhone的UITableView,细胞和通知 - 通知

我已经建立了这样的结构:在我TableViewController我做self.tableview一个监听到NSNotification(初始化期间指定)。我已经创建了一个自定义单元格视图,其中一个名为firstLoad的额外属性在初始化期间被设置为YES。在我的tableView cellForRowAtIndexPath中,我正在检查firstload属性,如果它设置为yes,我调用一个函数从url下载图像。当发生这种情况时,会发出一个通知,由tableviewcontroller中的函数捕获,我得到indexpathsforvisiblerows,并且如果通知中的行与其中一个indexpathsforvisiblerows数组中的行匹配,那么我会设置单元格的图像,然后重新加载Data

我遇到的麻烦是,当我开始滚动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]; 
    }); 
    }]; 
} 
+0

这听起来好像填充重复使用的单元格有点怪异。但是,没有任何代码,它将很难帮助你。我猜,cellForRowAtIndexPath和属于它的所有代码都是最有帮助的。 – Phlibbo

+0

@Phlibbo刚刚更新了代码示例!谢谢参观!! – MrMaksimize

+0

坦率地说,你的代码看起来有点混乱,但我试图理解它。你知道如何重复使用细胞,不是吗?即使您的表格中有100行,也可能只有6个单元格,这些单元格一次又一次地使用。所以,我认为你的'firstUsed'属性有问题。你用它来查看图像是否已经加载,对吗?但是如果你只有例如6个单元格(具有6个'firstUsed')属性,但是有100个图像,但某些内容会出错:)我希望在这里我是正确的,可能还有其他错误,但首先请看一下。 – Phlibbo

好吧,首先,在firstLoad -flag您正在使用没有意义。你需要知道你的图像是否已经被加载,但由于可重用的单元格不能与特定的图像连接,所以这不是做到这一点的方法。

你更新你的帖子了几次,现在,它是不完全清楚你目前的问题是什么。所以我只想为您提供一个适当和干净的解决方案: 首先,您需要一个地方来存储您的图像。 A NSMutableDictionary将服务得很好。使用这些键存储您的URL和存储图像的值。 当你输入一个新的单元格时,看看URL是否已经在字典中。如果是这样,只需填写它。否则,开始加载过程。如果您这样做,您还应该在字典中创建一个新条目,该条目存储图像的URL和nil。这可以帮助您避免使用尚未准备好的图像加载两次。在“加载完成”方法中,您将图像替换为nil值。 而这应该是它。当然,您需要根据您的具体需求量身定制这些步骤,但这不应该成为一个问题。希望这可以帮助!

PS:另外,你应该检查你的代码,找出多余或过于复杂的呼叫。不知道你的具体设置,迭代NSIndexPath看起来很奇怪,你应该能够直接访问你的值。

+0

首先非常感谢回复。但是,如果您注意到,这正是上述retrieveImageWithUrl函数中正在执行的操作。我确实让它工作,通过在tableview本身创建一个imageCache属性并通过indexpath键入它。这种方式retrieveImageWithUrl永远不会运行,除非没有该索引路径的对象。我摆脱了第一个负担,你说得对。另外,哈哈,你如何直接从indexpath中取出值而不是for循环?我看了看文档,并没有得到一个好的解决方案。 – MrMaksimize

这可能是该从表格视图中取出的单元格保留了它们在其公关中的图像一生一世。尝试将imageview图像设置为cellForRowAtIndexPath中的nil(在将其更新为可能需要一些时间的新图像之前)。

+0

ahh但是如果我将图像设置为零,那么我必须将单元格的firstLoad属性设置为YES,以便可以加载图像。那会让控制器陷入无限循环 – MrMaksimize