Представление списка SwiftUI не обновляется после обновления сущности Core Data в другом представлении - PullRequest
0 голосов
/ 19 марта 2020

У меня есть сущность Урока, хранящаяся в Базовых данных, одна из переменных которой - хранить, завершен ли урок.

Уроки перечислены в списке SwiftUI и при выборе go к Виду, где существует игра. Как только игра завершена, переменная 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()
            }


   }
}

То, что я пробовал:

  1. Принудительная перезагрузка списка с уведомлениями и .onReceive
  2. Настройка урока NSManagedObject с помощью функции setComplete, который вызывает 'objectWillChange'
  3. Делая @FetchRequest более подробным, добавив true и false для полной переменной

Буду признателен за любые предложения, как решить эту проблему. Я новичок в SwiftUI, поэтому заранее спасибо за вашу помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...