2016-06-11 3 views
2

Когда я пытаюсь удалить элемент из базы данных Realm, я не могу соответствующим образом обновить UICollection View.Обновление UICollectionView после удаления объекта Realm

Давайте предположим, что царством контейнер children типа List<Child>:

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

Когда я хочу, чтобы удалить этот ребенок из базы данных:

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

обновление CollectionView по collectionView.deleteItemsAtIndexPaths([indexPath]) дает следующее сообщение об ошибке:

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

T он только так, как я получаю обновленный collectionView, с помощью collectionView.reloadData(), но это не то, что я хочу, поскольку анимация удаления ячейки отсутствует.

Однако, когда я только удалить ребенка из этого контейнера в indexPath.row (без его удаления из базы данных) по:

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

обновление CollectionView с collectionView.deleteItemsAtIndexPaths([indexPath]) работает без проблем.

Что было бы лучшим способом обновить UICollectionView после удаления элемента из базы данных?

+0

Проблема: вы сначала удаляете ее из children.removeAtIndex (indexPath.row). Тогда как возможно, что объект доступен в этом indexPath.row? –

+0

Это правда. Но на самом деле я не хочу использовать 'removeAtIndex' вообще, так как я хочу удалить его из базы данных. Я упомянул об этом, потому что это был единственный способ получить обновление collectionView. – Gerard

+0

Для перезагрузки коллекции вам нужно удалить объект из списка детей. Таким образом, просмотр коллекции получит новый список. –

ответ

2

Ошибка, с которой вы сталкиваетесь, появляется, когда вы продолжаете доступ к объекту, который уже был удален. Таким образом, вы скорее всего сохраняете ссылку на свой объект, что само по себе прекрасно, но продолжайте обращаться к нему после того, как оно было invalidated.

Это может произойти, например. в вашем пользовательском подклассе UICollectionViewCell. Я бы рекомендовал реализовать сеттер в своей ячейке и вытащить из этого метода значения свойств в ваши компоненты представления. Вы можете даже использовать 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

Удаленный объект действительно был вызван в ячейке UICollectionView в «layoutSubviews». Я не ожидал, что этот метод был даже вызван после удаления, но использование сеттера вместо прямой ссылки разрешило проблему !!! Что касается вашего предложения использовать уведомление, у меня все еще есть проблема с его внедрением. Я получаю сообщение об ошибке: '...Количество элементов, содержащихся в существующем разделе после обновления (5), должно быть равно количеству элементов, содержащихся в этом разделе, перед обновлением (6), плюс или минус количество элементов, вставленных или удаленных из этого раздела (1 вставлен , 1 удалено) ... ' – Gerard

+0

Поскольку я только удаляю элемент, я не понимаю, почему обработчик уведомлений, по-видимому, также вставляет элемент. Не могли бы вы также дать мне подсказку? – Gerard

+0

Выполняете пакетные обновления в любом другом месте вашего кода? – marius

Смежные вопросы