我正在构建一个基本的笔记应用程序,该应用程序的主页应显示用户笔记的列表。注释由Note类(Core数据生成的类)表示。 (我的最终目标是通过NSPersistentCloudKitContainer与CloudKit同步的Notes应用。)
到目前为止,当用户加载应用程序时,列表将显示正确的注释数据。但是,当我尝试通过点击newNoteButton
来创建新笔记时,笔记数组会更改,但是我的UI不会改变。我必须重新加载应用程序才能看到新笔记。我可能做错了什么?对不起,下面的代码很混乱:
NoteList.swift
struct NoteList: View {
@EnvironmentObject var userNotes: UserNotes
var newNoteButton: some View {
Button(action: {
self.userNotes.createNewNote()
self.userNotes.objectWillChange.send()
}) {
Image(systemName: "plus")
.imageScale(.large)
.accessibility(label: Text("New Note"))
}
}
var body: some View {
NavigationView {
List {
ForEach(self.userNotes.notes) { note in
NavigationLink(destination: NoteDetail(note: self.$userNotes.notes[self.userNotes.notes.firstIndex(of: note)!])) {
Text(note.unsecuredContent!)
}
}
}
.navigationBarTitle(Text("Notes"), displayMode: .inline)
.navigationBarItems(trailing: newNoteButton)
}
}
}
UserNotes.swift
class UserNotes: NSObject, ObservableObject {
@Published var notes: [Note] = []
var managedObjectContext: NSManagedObjectContext? = nil
var fetchedResultsController: NSFetchedResultsController<Note> {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
let fetchRequest: NSFetchRequest<Note> = Note.fetchRequest()
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: "unsecuredContent", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: self.managedObjectContext!,
sectionNameKeyPath: nil, cacheName: "Master")
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
do {
try _fetchedResultsController!.performFetch()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController<Note>? = nil
override init() {
super.init()
managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
notes = fetchedResultsController.sections![0].objects as! [Note]
}
func createNewNote() {
let newNote = Note(context: managedObjectContext!)
// If appropriate, configure the new managed object.
newNote.unsecuredContent = "New CloudKit note"
// Save the context.
do {
try managedObjectContext!.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
extension UserNotes: NSFetchedResultsControllerDelegate {
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
notes = controller.sections![0].objects as! [Note]
}
}
Note.swift(由Core Data生成)
// This file was automatically generated and should not be edited.
//
import Foundation
import CoreData
@objc(Note)
public class Note: NSManagedObject {
}
Note.swift(扩展名)
extension Note: Identifiable {}
答案 0 :(得分:0)
在@dfd的帮助下(请参见here),我可以通过将Combine导入到我的UserNotes类,添加objectWillChange
并调用objectWillChange.send()
来解决此问题:
import Foundation
import UIKit
import CoreData
import Combine
class UserNotes: NSObject, ObservableObject {
var objectWillChange = PassthroughSubject<Void, Never>()
@Published var notes: [Note] = [] {
willSet {
objectWillChange.send()
}
}
var managedObjectContext: NSManagedObjectContext? = nil
var fetchedResultsController: NSFetchedResultsController<Note> {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
let fetchRequest: NSFetchRequest<Note> = Note.fetchRequest()
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: "unsecuredContent", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: self.managedObjectContext!,
sectionNameKeyPath: nil, cacheName: "Master")
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
do {
try _fetchedResultsController!.performFetch()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController<Note>? = nil
override init() {
super.init()
managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
notes = fetchedResultsController.sections![0].objects as! [Note]
}
func createNewNote() {
let newNote = Note(context: managedObjectContext!)
// If appropriate, configure the new managed object.
newNote.unsecuredContent = UUID().uuidString // Just some random crap
// Save the context.
do {
try managedObjectContext!.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
extension UserNotes: NSFetchedResultsControllerDelegate {
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
notes = controller.sections![0].objects as! [Note]
}
}
答案 1 :(得分:0)
使用SwiftUI,提取的结果控制器将进入View
,如下所示:
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: Note.entity(), sortDescriptors: []) var notes: FetchedResults<Note>
var body: some View {
VStack{
List{
ForEach(notes, id: \.self) { note in
...
}
}
}
}
您也可以执行Note(self.moc)
在View
中创建新笔记,例如在按钮处理程序中,不需要该帮助程序类。