代码之家  ›  专栏  ›  技术社区  ›  Eugene

当我的@Published NSManagedObject数组更改时,我的SwiftUI列表不会更新

  •  0
  • Eugene  · 技术社区  · 5 年前

    我正在构建一个基本的笔记应用程序,我的应用程序主页应该显示用户笔记的列表。note用note类表示,note类是一个核心数据生成类。(我的最终目标是通过NSPersistentCloudKitContainer与CloudKit同步的notes应用。)

    到目前为止,当用户加载应用程序时,列表会显示正确的notes数据。然而,当我试图通过点击我的 newNoteButton ,注释数组会发生变化,但我的用户界面不会发生变化。我必须重新加载应用才能看到新的便条。我可能做错了什么?抱歉,下面的代码太乱了:

    记事本。敏捷的

    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)
        }
      }
    
    }
    

    用户笔记。敏捷的

    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]
      }
    
    }
    

    笔记swift(由核心数据生成)

    //  This file was automatically generated and should not be edited.
    //
    
    import Foundation
    import CoreData
    
    @objc(Note)
    public class Note: NSManagedObject {
    
    }
    

    笔记斯威夫特(分机)

    extension Note: Identifiable {}
    
    0 回复  |  直到 5 年前
        1
  •  0
  •   Eugene    5 年前

    在@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]
      }
    
    }
    
    
        2
  •  0
  •   malhal Benzy Neez    5 年前

    使用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) 创建新的便笺 看法 e、 g.在按钮处理程序中,不需要该助手类。