ios - Updating UICollectionView after deleting a Realm object -
when try delete item realm database unable update uicollection view appropriately.
lets assume realm container children
of type list<child>
:
var children = realm.objects(parent).first!.children
when want remove child database by:
try! realm.write { realm.delete(children[indexpath.row]) }
updating collectionview collectionview.deleteitemsatindexpaths([indexpath])
gives following error:
got error: *** terminating app due uncaught exception 'rlmexception', reason: 'object has been deleted or invalidated.'
the way collectionview updated using collectionview.reloaddata()
, not want since animation of cell deletion missing.
however, when remove child container @ indexpath.row
(without removing database) by:
try! realm.write { children.removeatindex(indexpath.row) }
updating collectionview collectionview.deleteitemsatindexpaths([indexpath])
works without problems.
what best way update uicollectionview after removing item database?
the error you're facing appears when keep accessing object, deleted. so, you're storing somewhere reference object, fine per se, keep accessing after invalidated
.
that happen e.g. in custom subclass of uicollectionviewcell
. i'd recommend implement setter on cell , pull method property values view components. can use kvo in cell update these. (we've an example based on reactkit in our repo.) can't though keep accessing properties when object might deleted @ later point in time, e.g. if cell needs drawn or layout when faded out.
i'd recommend subscribe fine-grained notifications list you're using fill collection view's cells , propagate updates in way collection view. in way can make sure items removed nice animation requested , automatically taken care of. put seen below. on @ our repo, you'll find 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 populated , can accessed without blocking ui collectionview.reloaddata() break case .update(_, let deletions, let insertions, let modifications): // query results have changed, apply them 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): // error occurred while opening realm file on 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 } }
Comments
Post a Comment