【发布时间】:2026-02-22 16:20:04
【问题描述】:
@FetchRequest 上有许多问题的答案提供了强制 SwiftUI 重绘视图的变通方法。我找不到任何解决这个问题的方法。
我的应用程序使用共享扩展将新项目插入我的 CoreData 模型 (sqlite)。在主应用程序和共享扩展目标之间共享一个框架。我的应用程序中的主要 SwiftUI ContentView 使用 @FetchRequest 属性来监视数据库的内容并更新视图:
struct ContentView: View {
@FetchRequest(fetchRequest: MyObj.allFetchRequest()) var allObjs: FetchedResults<MyObj>
...
}
我的 xcdatamodel 扩展为:
public static func allFetchRequest() -> NSFetchRequest<MyObj> {
let request: NSFetchRequest<MyObj> = MyObj.fetchRequest()
// update request to sort by name
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
return request
}
共享扩展使用以下方法添加新项目:
let newObj = MyObj(context: context)
newObj.name = "new name"
try! context.save()
使用共享扩展添加新项目后,当我通过在设备上切换应用返回我的应用时,SceneDelegate 检测到sceneDidBecomeActive。在这个函数中,我可以手动运行一个 fetch 请求并查看新项目是否已添加。我什至可以使用其他 SO 问题的答案来欺骗 UI 在 ContentView 中重建(通过在收到通知时切换构建器中使用的 Bool),但无论哪种情况,当 UI 重建时,allObjs 不包含来自数据库的更新结果。
在我的sceneDidBecomeActive 中,我尝试了多种代码组合,以尝试以@FetchRequest 可以看到的方式使用数据库的最新内容更新上下文。数据就在那里,我的托管上下文可以看到这个新数据,因为手动获取请求会返回新项目,但 @FetchRequest 始终是陈旧的,阻止了 UI 重建。在这两个位置,我都打印了上下文,并且确信它是相同的上下文。我试过了:
context.reset()context.refreshAllObjects()context.save()
我不知道为什么@FetchRequest 在ContentView 重绘时没有更新其值。
如何强制@FetchRequest 在我的共享扩展将新对象添加到数据库后更新其对象并导致 SwiftUI 重建?
(Xcode 11.4.1,Swift 5,目标:iOS 13.1)
编辑:
在我的ContentView 中,我打印了allObjs 变量、它们的状态、上下文的内存地址等。现有对象是相同的,除了新的 fetch 显示新添加的对象,而 allObjs 不包含新对象。很明显@FetchRequest 对象没有得到更新。
编辑 2:
我尝试使用@Published 属性和显式update() 方法创建自定义ObservableObject 类,然后将其用作ContentView 中的@ObservedObject。这行得通。
class MyObjList: ObservableObject {
static let shared = MyObjList()
@Published var allObjs: [MyObj]!
init() {
update()
}
func update() {
allObjs = try! DataStore.persistentContainer.viewContext.fetch(MyObj.allFetchRequest())
}
}
然后在ContentView:
@EnvironmentObject var allObjs: MyObjList
这有助于确认数据存在,只是@FetchRequest 没有正确更新它。这是一种实用的解决方法。
【问题讨论】:
-
如果您在应用内添加相同的对象(不是扩展),它会出现在@FetchRequest 中吗?
-
@Aspid 是的,在应用程序(不是扩展程序)中创建的相同对象出现没有问题。请记住,它是在
ContentView显示的相同上下文中创建的 -
我只是想知道这是否是 WAL 模式和 FRC 缓存问题的另一个例子。请参阅this answer 了解更多信息。
-
@pbasdf 我不知道的有趣的东西。我尝试了
let storeDescription = NSPersistentStoreDescription; storeDescription.setValue("DELETE" as NSString, forPragmaNamed: "journal_mode")并将描述添加到NSPersistentContainer(),但这并没有解决问题。 -
对不起。那是一个红鲱鱼。
标签: ios swift core-data swiftui