我在核心数据中存储了一个Lesson实体,其变量之一是存储课程是否完成。
课程列在SwiftUI列表中,选择后进入游戏所在的视图。游戏结束后,complete变量将更新为true。并且应该发生的是,列表视图显示列出的游戏,并在游戏旁边带有复选标记。
但是,发生的事情是,当我在游戏中保存课程的“完成”状态时(在tapRight方法中-参见下文),我得到警告:
[TableView]仅警告一次:通知UITableView布置其可见单元格和其他内容,而不必放在视图层次结构中(表视图或其父视图之一尚未添加到窗口中)。
然后,当我按下游戏视图顶部的导航按钮返回到视图视图时,我发现游戏已从列表中消失。
但是,当我关闭应用程序并重新打开它时,列表中包含游戏行和选中标记,因此我知道核心数据课程实例正在正确更新。下面的列表视图代码。
import SwiftUI
import CoreData
import UIKit
struct LessonList: View {
@Environment(\.managedObjectContext) var moc
@State private var refreshing = false
private var didSave = NotificationCenter.default.publisher(for: .NSManagedObjectContextDidSave)
@FetchRequest(entity: Lesson.entity(), sortDescriptors: [], predicate: NSPredicate(format: "(type == %@) AND (stage == %@) AND ((complete == %@) OR (complete == %@))", "phonicIntro", "1", NSNumber(value: true), NSNumber(value: false) )) var phonicIntroLessons1: FetchedResults<Lesson>
var body: some View {
NavigationView {
List {
self.stage1Section
}
.navigationBarTitle("Lessons")
}
}
private var phonicIntroLink : some View {
ForEach(phonicIntroLessons1) { lesson in
NavigationLink(destination: PhonicIntroGame(lesson: lesson)) {
LessonRow(lesson: lesson)
}
}
}
private var stage1Section : some View {
Section(header: Text("Stage 1")) {
phonicIntroLink
}.onReceive(self.didSave) { _ in
self.refreshing.toggle()
}
}
游戏视图中用于保存完成状态的相关代码:
import SwiftUI
import AVFoundation
struct PhonicIntroGame: View {
@Environment(\.managedObjectContext) var moc
var lesson: Lesson?
func tapRight() {
if ((self.lesson?.phonicsArray.count ?? 1) - 1) > self.index {
self.index = self.index + 1
print("This is index \(self.index)")
//On completion
if (index + 1) == (lesson!.phonicsArray.count) {
self.lessonComplete()
}
} else {
print(self.index)
func lessonComplete() {
self.lesson?.setComplete(true)
self.saveLesson()
}
func saveLesson() {
do {
try moc.save()
} catch {
print("Error saving context \(error)")
}
}
在NSManagedObject子类中:
extension Lesson {
func setComplete (_ state: Bool) {
objectWillChange.send()
self.complete = state
}
}
lessonRow的代码如下:
import SwiftUI
import CoreData
struct LessonRow: View {
@Environment(\.managedObjectContext) var moc
@State var refreshing1 = false
var didSave = NotificationCenter.default.publisher(for: .NSManagedObjectContextDidSave)
var lesson: Lesson
var body: some View {
HStack {
Image(lesson.wrappedLessonImage )
.resizable()
.frame(width: 80, height: 80)
.cornerRadius(20)
Text(lesson.wrappedTitle)
.font(.system(size: 20))
.fontWeight(.thin)
.padding()
if lesson.complete == true {
Image(systemName: "checkmark.circle")
.resizable()
.frame(width: 30, height: 30)
.foregroundColor(.green)
} else {
Rectangle()
.frame(width: 30, height: 30)
.foregroundColor(.clear)
}
}.padding()
.onReceive(self.didSave) { _ in
self.refreshing1.toggle()
}
}
}
我尝试过的事情:
对于解决此问题的任何建议,我将不胜感激。我是SwiftUI的新手,所以在此先感谢您的帮助。
答案 0 :(得分:1)
是的,我最终解决此问题的方法是将@ObservedObject添加到PhonicIntroGame:View中的存储对象中。如下-
@ObservedObject var lesson: Lesson
答案 1 :(得分:0)
Core Data 批量更新不会更新内存中的对象。之后您必须手动刷新。
批量操作绕过普通的 Core Data 操作,直接在底层 SQLite 数据库(或任何支持持久存储的数据库)上操作。他们这样做是为了提高速度,但这意味着他们也不会触发您使用正常获取请求获得的所有内容。
您需要执行 Apple 的 Core Data Batch Programming Guide:Implementing Batch Updates - Updating Your Application After Execution 中所示的操作