2011-10-11 96 views
0

後的細胞無法顯示正確的圖像所以我難倒就這個問題和不知道該怎麼辦的最好方式,這是。我需要從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

回答

1

好吧,首先,在firstLoad -flag您正在使用沒有意義。你需要知道你的圖像是否已經被加載,但由於可重用的單元格不能與特定的圖像連接,所以這不是做到這一點的方法。

你更新你的帖子了幾次,現在,它是不完全清楚你目前的問題是什麼。所以我只想爲您提供一個適當和乾淨的解決方案: 首先,您需要一個地方來存儲您的圖像。 A NSMutableDictionary將服務得很好。使用這些鍵存儲您的URL和存儲圖像的值。 當你輸入一個新的單元格時,看看URL是否已經在字典中。如果是這樣,只需填寫它。否則,開始加載過程。如果您這樣做,您還應該在字典中創建一個新條目,該條目存儲圖像的URL和nil。這可以幫助您避免使用尚未準備好的圖像加載兩次。在「加載完成」方法中,您將圖像替換爲nil值。 而這應該是它。當然,您需要根據您的具體需求量身定製這些步驟,但這不應該成爲一個問題。希望這可以幫助!

PS:另外,你應該檢查你的代碼,找出多餘或過於複雜的呼叫。不知道你的具體設置,迭代NSIndexPath看起來很奇怪,你應該能夠直接訪問你的值。

+0

首先非常感謝回覆。但是,如果您注意到,這正是上述retrieveImageWithUrl函數中正在執行的操作。我確實讓它工作,通過在tableview本身創建一個imageCache屬性並通過indexpath鍵入它。這種方式retrieveImageWithUrl永遠不會運行,除非沒有該索引路徑的對象。我擺脫了第一個負擔,你說得對。另外,哈哈,你如何直接從indexpath中取出值而不是for循環?我看了看文檔,並沒有得到一個好的解決方案。 – MrMaksimize

0

這可能是該從表格視圖中取出的單元格保留了它們在其公關中的圖像一生一世。嘗試將imageview圖像設置爲cellForRowAtIndexPath中的nil(在將其更新爲可能需要一些時間的新圖像之前)。

+0

ahh但是如果我將圖像設置爲零,那麼我必須將單元格的firstLoad屬性設置爲YES,以便可以加載圖像。那會讓控制器陷入無限循環 – MrMaksimize