2016-06-11 99 views
2

當我嘗試從Realm數據庫中刪除項目時,我無法適當更新UICollection View。刪除Realm對象後更新UICollectionView

讓我們假設一個境界容器List<Child>類型的children

var children = realm.objects(Parent).first!.children 

當我想從數據庫中刪除這個孩子:

try! realm.write { 
    realm.delete(children[indexPath.row]) 
} 

collectionView.deleteItemsAtIndexPaths([indexPath])更新的CollectionView提供了以下錯誤:

Got error: *** Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.' 

T他只能通過使用collectionView.reloadData()來獲取更新的collectionView,但這不是我想要的,因爲缺少單元格刪除的動畫。

然而,當我只能在這個容器中,在indexPath.row通過移除子(不從數據庫中刪除它):

try! realm.write { 
    children.removeAtIndex(indexPath.row) 
} 

collectionView.deleteItemsAtIndexPaths([indexPath])作品更新的CollectionView沒有問題。

從數據庫中刪除項目後,更新UICollectionView的最佳方法是什麼?

+0

問題是你先從children.removeAtIndex(indexPath.row)中刪除它。那麼如何在indexPath.row中使用該對象? –

+0

這是真的。但事實上,我不想使用'removeAtIndex',因爲我想從數據庫中刪除它。我提到它是因爲這是我能夠使collectionView更新工作的唯一方法。 – Gerard

+0

要重新加載集合視圖,您必須從子列表中刪除對象。這樣集合視圖就會得到新的列表。 –

回答

2

當您繼續訪問已被刪除的對象時,會出現您正面臨的錯誤。所以,你可能在某處存儲了一個對象的引用,這本身就很好,但是在invalidated後繼續訪問它。

這可能發生,例如,在您的自定義子類UICollectionViewCell。我建議在你的單元上實現一個setter,並從該方法中將屬性值拉入你的視圖組件。您甚至可以在您的手機中使用KVO來更新這些。 (對於我們的回購,我們有an example based on ReactKit)。當對象可能在稍後的時間點被刪除時,您不能通過訪問屬性,例如,如果您的單元需要繪製或佈局時,它淡出。

我建議爲您用於填充集合視圖單元格的列表訂閱細粒度的通知,並且只將這種更新以這種方式傳播到集合視圖。通過這種方式,您可以確保您的物品將按照要求以良好的動畫進行移除,並自動處理。所有放在一起,這可能看起來像下面看到的。在我們的回購中,您會發現一個complete runnable sample

class Cell: UICollectionViewCell { 
    @IBOutlet var label: UILabel! 

    func attach(object: DemoObject) { 
     label.text = object.title 
    } 
} 

class CollectionViewController: UICollectionViewController { 
    var notificationToken: NotificationToken? = nil 

    lazy var realm = try! Realm() 
    lazy var results: Results<DemoObject> = { 
     self.realm.objects(DemoObject) 
    }() 


    // MARK: View Lifecycle 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Observe Notifications 
     notificationToken = results.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in 
      guard let collectionView = self?.collectionView else { return } 
      switch changes { 
      case .Initial: 
       // Results are now populated and can be accessed without blocking the UI 
       collectionView.reloadData() 
       break 
      case .Update(_, let deletions, let insertions, let modifications): 
       // Query results have changed, so apply them to the UITableView 
       collectionView.performBatchUpdates({ 
        collectionView.insertItemsAtIndexPaths(insertions.map { NSIndexPath(forRow: $0, inSection: 0) }) 
        collectionView.deleteItemsAtIndexPaths(deletions.map { NSIndexPath(forRow: $0, inSection: 0) }) 
        collectionView.reloadItemsAtIndexPaths(modifications.map { NSIndexPath(forRow: $0, inSection: 0) }) 
       }, completion: { _ in }) 
       break 
      case .Error(let error): 
       // An error occurred while opening the Realm file on the background worker thread 
       fatalError("\(error)") 
       break 
      } 
     } 
    } 

    deinit { 
     notificationToken?.stop() 
    } 


    // MARK: Helpers 

    func objectAtIndexPath(indexPath: NSIndexPath) -> DemoObject { 
     return results[indexPath.row] 
    } 


    // MARK: UICollectionViewDataSource 

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return results.count 
    } 

    override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { 
     let object = objectAtIndexPath(indexPath) 
     try! realm.write { 
      realm.delete(object) 
     } 
    } 

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 
     let object = objectAtIndexPath(indexPath) 
     let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! Cell 
     cell.attach(object) 
     return cell 
    } 

} 
+0

刪除的對象確實在「layoutSubviews」的UICollectionView單元格中調用。我沒想到這種方法甚至在刪除後被調用,但使用setter而不是直接引用解決了問題!關於您使用通知的建議,我仍然遇到了實施該問題的問題。我收到錯誤:'...在更新之後(5),現有部分中包含的項目數量必須等於更新前部分中包含的項目數量(6),加上或減去從該部分插入或刪除的項目數量(插入1個,1刪除)...' – Gerard

+0

由於我只刪除一個項目,我不明白爲什麼通知處理程序顯然插入一個項目。你能否在這裏給我一點提示? – Gerard

+0

您是否在代碼中的任何其他地方執行批量更新? – marius