По @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
. В этой функции я могу вручную запустить запрос на выборку и увидеть, что новый элемент был добавлен. Я даже могу использовать ответы на другие вопросы SO, чтобы заставить пользовательский интерфейс перестроить в ContentView (путем переключения Bool, используемого в построителе при получении уведомления), но в любом случае, когда пользовательский интерфейс перестраивается, allObjs
не содержит обновленные результаты из базы данных.
В моем sceneDidBecomeActive
я пробовал множество комбинаций кода, чтобы попытаться обновить контекст последним содержимым базы данных таким образом, чтобы @FetchRequest
его увидел. Данные есть, и мой управляемый контекст может видеть эти новые данные, потому что запрос ручной выборки возвращает новый элемент, но @FetchRequest
всегда устарел, предотвращая перестроение пользовательского интерфейса. В обоих местах я распечатал контекст и уверен, что это тот же контекст. Я пробовал:
context.reset()
context.refreshAllObjects()
context.save()
Я в растерянности относительно того, почему @FetchRequest
не обновляет свои значения, когда ContentView
redr aws.
Как я могу заставить @FetchRequest
обновить свои объекты и вызвать перестройку SwiftUI после того, как мое расширение общего ресурса добавляет новый объект в базу данных?
(Xcode 11.4.1, Swift 5, цель: iOS 13.1)
редактировать:
В моем ContentView
, я печатаю allObjs
переменные, их состояние, адрес в памяти контекста, и c. Я сравниваю это с новой выборкой из контекста, и все значения для существующих объектов являются то же самое, за исключением того, что новая выборка показывает только что добавленный объект, тогда как allObjs
не содержит новый объект. Совершенно ясно, что объект @FetchRequest
не обновляется.
изменить 2:
Я попытался создать собственный класс ObservableObject
со свойством @Published
и явным методом update()
, а затем использовать его как @ObservedObject
дюйм ContentView
. Это работает.
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
. Это функциональный обходной путь.