dro*_*ang 11 core-data ios swift swiftui
@FetchRequest 上有很多问题的答案提供了强制 SwiftUI 重绘视图的解决方法。我找不到解决这个问题的任何内容。
我的应用程序使用共享扩展将新项目插入到我的CoreData模型 (sqlite) 中。框架在主应用程序和共享扩展目标之间共享。ContentView我的应用程序中的主要 SwiftUI使用一个@FetchRequest属性来监视数据库的内容并更新视图:
struct ContentView: View {
@FetchRequest(fetchRequest: MyObj.allFetchRequest()) var allObjs: FetchedResults<MyObj>
...
}
Run Code Online (Sandbox Code Playgroud)
我的 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
}
Run Code Online (Sandbox Code Playgroud)
共享扩展使用以下方法添加一个新项目:
let newObj = MyObj(context: context)
newObj.name = "new name"
try! context.save()
Run Code Online (Sandbox Code Playgroud)
使用共享扩展添加新项目后,当我通过在设备上切换应用程序返回到我的应用程序时,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)
编辑:
在 my 中ContentView,我打印allObjs变量、它们的状态、上下文的内存地址等。我将其与从上下文中新提取的值进行比较,并且现有对象的所有值都相同,除了新提取显示新添加的对象,而allObjs没有包含新的对象。很明显,该@FetchRequest对象没有得到更新。
编辑2:
我尝试创建一个ObservableObject带有@Published属性和显式update()方法的自定义类,然后将其用作@ObservedObjectin ContentView。这有效。
class MyObjList: ObservableObject {
static let shared = MyObjList()
@Published var allObjs: [MyObj]!
init() {
update()
}
func update() {
allObjs = try! DataStore.persistentContainer.viewContext.fetch(MyObj.allFetchRequest())
}
}
Run Code Online (Sandbox Code Playgroud)
然后在ContentView:
@EnvironmentObject var allObjs: MyObjList
Run Code Online (Sandbox Code Playgroud)
这有助于确认数据在那里,只是没有被@FetchRequest. 这是一个功能性的解决方法。
Asp*_*eri -1
如果适用于您的应用程序,请尝试移动ContentView应用程序上的创建转到前台(因此将从头开始重新创建获取请求)
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// leave here only window creation
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
self.window = window
}
}
// ... other code here
func sceneWillEnterForeground(_ scene: UIScene) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let contentView = ContentView().environment(\.managedObjectContext, context)
let controller = UIHostingController(rootView: contentView)
window?.rootViewController = controller
window?.makeKeyAndVisible()
}
Run Code Online (Sandbox Code Playgroud)