ios - 删除 Realm 对象后更新 UICollectionView

标签 ios swift realm

当我尝试从 Realm 数据库中删除项目时,我无法适本地更新 UICollection View 。

让我们假设一个 Realm 容器 children类型 List<Child> :

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

当我想通过以下方式从数据库中删除这个 child 时:

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.'

我更新 collectionView 的唯一方法是使用 collectionView.reloadData() ,但这不是我想要的,因为缺少单元格删除的动画。

但是,当我只从这个位于 indexPath.row 的容器中移除一个 child 时(不将其从数据库中删除)通过:

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

collectionView.deleteItemsAtIndexPaths([indexPath]) 更新 collectionView工作没有问题。

从数据库中删除项目后更新 UICollectionView 的最佳方法是什么?

最佳答案

当您继续访问一个已被删除的对象时,就会出现您遇到的错误。因此,您可能在某个地方存储了对对象的引用,这本身很好,但在它成为 invalidated 之后继续访问它。 .

这可能会发生,例如在 UICollectionViewCell 的自定义子类中。我建议在您的单元格上实现一个 setter ,并从该方法中将属性值提取到您的 View 组件中。你甚至可以在你的单元格中使用 KVO 来更新这些。 (我们在 repo 协议(protocol)中为此设置了 an example based on ReactKit。)当对象可能在稍后的某个时间点已被删除时,您不能继续访问属性,例如如果您的单元格在淡出时需要绘制或布局。

我建议订阅用于填充 Collection View 单元格的列表的细粒度通知,并且仅以这种方式将更新传播到 Collection View 。通过这种方式,您可以确保您的项目将根据要求以漂亮的动画被移除,并且它会自动得到处理。所有这些放在一起看起来如下所示。在我们的仓库中,您会找到一个 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
    }

}

关于ios - 删除 Realm 对象后更新 UICollectionView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37761624/

相关文章:

ios - 一次性将所有 Realm 对象转换为字典

ios10、Swift 3 和 Firebase 推送通知 (FCM)

ios - 将结构作为核心数据实体的属性

ios - 实现 'WKNavigationDelegate' 方法 'didReceiveServerRedirectForProvisionalNavigation' 方法以遵循重定向的示例

iOS Realm : How do i downcast to Object

Swift 4 Realm Swift 对象

ios - 使用 Xcode 5 编译 live555 和 ffmpeg

ios - 触摸一次后如何使 UIButton 不可点击并隐藏和取消隐藏按钮? - swift

ios - 如果我们使用多个文本字段,如何自动获取 OTP

ios - 第一次调用时出现CallKit错误7