2013-03-20 56 views
1

這就是問題所在:我在保存並將縮略圖提取到Core Data後更新我的tableview,然後告訴單元更新自身 - 因此它可以在圖像加載到時顯示縮略圖核心數據。我使用兩個不同的線程作爲核心數據不是線程安全的,當然所有的GUI元素都需要在主線程中發生。iOS:更新tableViewCell無限循環

但是這整個方法只是永遠保持循環,並是什麼原因造成的,當我重新加載線程:

[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 

爲什麼?我該如何解決這個問題?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Photo"]; 
    Photo *photo = [self.fetchedResultsController objectAtIndexPath:indexPath];  
    cell.textLabel.text = photo.title; 
    cell.detailTextLabel.text = photo.subtitle; 

    NSLog(@"Context %@", self.photographer.managedObjectContext); 
    [self.photographer.managedObjectContext performBlock:^{ 
     [Photo setThumbnailForPhoto:photo]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      cell.imageView.image = [UIImage imageWithData:photo.thumbnail]; 
      [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
     }); 
    }]; 
    return cell; 
} 
+0

不要,我再說一遍,不要在cellforrowatindexpath內調用重載表(cell)函數..因爲它會一遍又一遍地讀取圖像。當你重新加載tableview或任何單元格時,它會再次調用cellforrowatindexpath(並且在你的情況下再次調用) – 2013-03-20 15:13:43

+0

cellForRowAtIndexPath將在繪製單元格之前調用。所以它已經更新了。爲什麼你需要在cellForRowAtIndexPath中重新加載? – Mert 2013-03-20 15:15:28

+0

Mert:我只是應該重新加載它,因爲我直接訪問了tableViewCell。 – 2013-03-20 15:22:04

回答

3

無限循環再次調用cellForRowAtIndexPath:的獲取被加載並在某小區重裝被稱爲後引起的。

重新載入將迫使cellForRowAtIndexPath:再次被調用...並且在你的情況下一次又一次地無限。

解決方案很簡單...不要在cellForRowAtIndexPath中重新加載單元格,而是在fetchrequest的回調方法中重新加載。然後重新加載它,而不是創建單元格。

相反,根本不要在cellForRowAtIndexpath:之內加載圖像。 每當您的表被實例化時,都會創建一個循環遍歷數據源並獲取每個項目的相應單元格的方法。然後爲您認爲需要的每個單元格加載圖像。並且在完成項目的提取時重新加載單元格(例如回調方法)。

如果您確實希望將圖像加載到單元格創建中,就像您現在所做的那樣(儘管我不認爲這是正確的方法)。你可以圍繞整個performBlock:用if語句檢查圖像是否已經被設置。

+0

聽起來不錯!但是......我只是意識到我不知道什麼是回調方法...... – 2013-03-20 15:21:08

+0

回調方法是一種在您的fetchresult完成時調用的方法。在這種情況下獲取圖像。事情是,你需要在cellForRowIndexpath之外加載圖像 – 2013-03-20 15:23:25

+0

他正在對主隊列執行異步調度,因爲回調已經完成。 – 2013-03-20 15:28:48

1

正如其他人已經說過的那樣,圖像加載完成後不需要調用reloadRowsAtIndexPaths。向cell.imageView.image分配新圖像就足夠了。

但是你的代碼還有另一個問題。我假設self.photographer.managedObjectContext是「專用併發類型」的受管對象上下文,因此performBlock在後臺線程上執行。 (否則不需要使用dispatch_async(dispatch_get_main_queue(), ...)。)

因此performBlock:在後臺線程上異步執行代碼。 (這是很好的,因爲用戶界面沒有被阻塞。)但是當圖像在一段時間後被提取時,單元格可能被重用用於不同的行。 (如果您滾動表格視圖時會發生這種情況,以便在獲取圖像時該行不可見。)

因此,你必須要檢查電池仍然在tableview中的相同位置:

[self.photographer.managedObjectContext performBlock:^{ 
    [Photo setThumbnailForPhoto:photo]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     if ([[tableView indexPathForCell:cell] isEqualTo:indexPath]) { 
      cell.imageView.image = [UIImage imageWithData:photo.thumbnail]; 
     } 
    }); 
}]; 
1

我將以下代碼:

cell.imageView.image = [UIImage imageWithData:photo.thumbnail]; 
    [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 

有了:

UITableViewCell *blockCell = [tableView cellForRowAtIndexPath:indexPath]; 
    blockCell.imageView.image = [UIImage imageWithData:photo.thumbnail]; 
    [blockCell setNeedsLayout]; 

這就解決了遞歸重裝的問題,以及cell在此期間得到了重用。我也會檢查你是否已經加載照片數據,如果沒有更新。

由於您使用的是NSFetchedResultsController,如果代表回調函數已經在照片數據更新時通知您,最好使用Totomus Maximus的答案。這種方式只是更新圖像視圖,並不會更新照片更新方法可能更改的任何其他信息。