在今天的扩展中创建记录并在应用程序中更新记录时的更改在今天的扩展中不可见

Changes when record was created in today extension and updated in app are not visible in today extension

简单地说,我有一个应用程序,今天是扩展程序。我还有两个实体:GoalService.

@objc(Goal)
class Goal: NSManagedObject {

    @NSManaged var identifier: String
    @NSManaged var startDate: Date
    @NSManaged var endDate: Date

    private var services: [Service] {
    
        let predicate = NSPredicate(format: "date >= %@ && date <= %@", startDate as NSDate, endDate as NSDate)

        return Service.mr_findAll(with: predicate) as! [Service]
    }

    var duration: Int64 {
        return services.reduce(0) { [=10=] + .duration }
    }
}

当我在 today extension 中创建与 goal 相关的 service 并在应用程序中更新它时,更新的结果在 today extension 中不可见,而在应用程序中正确显示。为什么?

这是我在扩展程序或扩展程序中创建和更新记录的方式:

MagicalRecord.save({ context in
        
    Service.createOrUpdate(withDuration: duration, date: Date(), identifier: identifier, in: context)
        
}, completion: { _, error in
        
        //do something on completion
})

扩展程序和应用程序是共享部分相同代码的不同程序。因此,两者都在创建自己的 persistentStoreCoordinator 和上下文。

通常在同一个应用程序中,您会有多个上下文都附加到同一个 persistentStoreCoordinator,其中一个的更改将由通过 notificationCenter 发出然后合并的通知处理。在这种情况下,有两个问题 - 1) notificationCenter 未在应用程序和扩展程序之间共享,因此它们无法轻松通信,以及 2) 上下文不共享相同的 persistentStoreCoordinator,因此您不能使用 ' mergeChangesFromContextDidSaveNotification` 即使您确实传递了该信息。

我以前没有尝试过,但这是我会尝试的:

  1. 设置某种方式来触发发生更改。有很多解决方案。
  2. 将您的 managedObjectContext(s) 设置为 stalenessInterval 为 0
  3. 当发生变化时,您必须更新您的核心数据。您可以通过在所有核心数据对象上调用 refreshObject:mergeChanges: 或进行另一次获取来完成此操作。诀窍是你必须从存储中获取上下文,从文件中获取存储,而不是命中两者之间的任何缓存。

根据@JonRose 的回答,我的问题的最终解决方案是:

获取我感兴趣的记录,在我从获取它们的同一上下文中刷新它们,然后再次获取它们:

private var services: [Service] {

    let predicate = NSPredicate(format: "date >= %@ && date <= %@", startDate as NSDate, endDate as NSDate)

    for service in Service.mr_findAll(with: predicate, in: NSManagedObjectContext.mr_rootSaving())! {
        NSManagedObjectContext.mr_rootSaving().refresh(service, mergeChanges: false)
    }

    return Service.mr_findAll(with: predicate) as! [Service]
}