【问题标题】:CoreStore how to observe changes in databaseCoreStore如何观察数据库的变化
【发布时间】:2019-08-09 11:24:12
【问题描述】:

我需要在导入发生后观察Entity 的变化。

目前我有下一个逻辑:

  1. 将带有临时标识符 (NSManagedObject.objectId) 的 Entity 保存到本地核心数据存储中。
  2. 通过AlamofirePOST请求将Entity发送到服务器。
  3. 服务器生成 JSON 并使用几乎相同的实体详细信息进行回复,但使用修改后的标识符(之前为 NSManagedObject.objectId)。因此本地的一个实体 id 将使用服务器 id 进行更新。
  4. 现在,当我收到新的 JSON 时,我会使用 transaction.importUniqueObjects

在这一步,我想通知我的数据源有关更改。并使用更新的标识符重新获取数据。

所以我的DataSource 在一个数组中有一些Entities,虽然我使用这个数据源来显示数据,但它仍然是我之前获取的那个数组中的静态信息,但是正如你在第 4 步中看到的那样,我已经更新了通过CoreStore导入核心数据存储,并希望DataSource的数组也能更新。

我在 CoreStore 中找到了一些关于 ListMonitor 的信息并尝试使用它。正如我所见,此方法在更新到来时有效

func listMonitorDidChange(_ monitor: ListMonitor)

但我尝试以某种方式重新获取数据。看起来监视器已经包含一些最新信息。

但是当我这样做时:

func listMonitorDidChange(_ monitor: ListMonitor<MyEntity>) {

    let entities = try? CoreStore.fetchAll(
                From<MyEntity>()
                    .orderBy(.ascending(\.name))
            ) // THERE IS STILL old information in database, but monitor instance shows new info.
    }

然后代码变成了这样:

func listMonitorDidChange(_ monitor: ListMonitor<MyEntity>) {

        var myEntitiesFromMonitor = [MyEntity]()

        for index in 0...monitor.numberOfObjects() {
            myEntitiesFromMonitor.append(monitor[index])
        }

        if myEntitiesFromMonitor.count > 0 {
            // HERE we update DataSource
            updateData(with: myEntitiesFromMonitor) 
        }

    }

不确定我是否走对了。

【问题讨论】:

  • 为什么需要在(托管)对象中存储一个额外的数组?监视器正在为您保存和更新它们,这就是您首先拥有它的原因。让您的数据源使用监视器来访问数据,而不是其他任何东西,否则您很容易遇到不一致的崩溃。
  • 好吧,让我看看。我刚刚通过 fetchAll 获取对象,但是是的,我想通过监视器处理对象是有意义的。
  • @MartinM 感谢您的建议!您的答案和 cmets 总是很有帮助!我之前考虑过这个问题。现在可以了,只是小问题可以通过监视器搜索吗?看起来应该有一些使用.where 条件的过滤器功能。只是想知道每次使用新的.where 条件重新初始化监视器都会很昂贵,例如每次我在搜索字段中输入字母以使用新数据更新表格视图时。

标签: ios swift core-data corestore


【解决方案1】:

如有错误请指正:

据我了解,每次核心数据更新为新更改时,监视器也会更新。我还没有深入研究它是如何通过一些 CoreData 上下文通知或其他方式实现的,但是在您通过 CoreStore 事务执行某些操作(例如创建或更新或删除对象或您想要的任何内容)之后,监视器会更新。它还具有您需要在类中实现的回调函数,您可以在其中观察数据模型的任何变化:

您的类,例如数据源或某些服务,甚至某些视图控制器(如果您不使用任何 MVVP 或 VIPER 或其他设计模式)需要遵守ListObserver 协议,以防您只想听一个对象。

这些功能如下:

    func listMonitorDidChange(monitor: ListMonitor<MyPersonEntity>) {
        // Here I reload my tableview and this monitor already has all needed info about sections and rows depend how you setup monitor.
        // So you classVariableMonitor which I provide below already has up to date state after any changes with data.
    }



    func listMonitorDidRefetch(monitor: ListMonitor<MyPersonEntity>) {
        // Not sure for which purposes it. I have not received this call yet
    }



typealias ListEntityType = ExerciseEntity

let classVariableMonitor = CoreStore.monitorSectionedList(
    From<ListEntityType>()
    .sectionBy(#keyPath(ListEntityType.muscle.name)) { (sectionName) -> String? in
        "\(String(describing: sectionName)) years old"
    }
        .orderBy(.ascending(\.name))
        .where(
            format: "%K == %@",
            #keyPath(ListEntityType.name),
            "Search string")
    )

所有其他内容都记录在 here 中,因此您可以在 tableview 数据源函数中找到如何从监视器中提取信息的信息。

感谢@MartinM 的建议!

【讨论】:

    猜你喜欢
    • 2019-10-26
    • 2019-03-18
    • 1970-01-01
    • 2019-03-01
    • 2011-07-03
    • 2012-02-22
    • 2018-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多