0

I have notes app using SwiftData also using CloudKit and the note editor is taking 125% CPU usage.

For example this is the note model:

@Model Class Note {
  var title: String = "" 
  var content: String = "" 
  var creationDate: Date = Date.now

  init(title: String = "", content: String = "") {
    self.title = title 
    self.content = content 
    self.creationDate = Date.now
  }
}

This is the NoteListView

struct NotesListView: View {
    @Query(sort: [
        SortDescriptor(\Note.creationDate, order: .reverse)
    ]) private var notes: [Note]

  @Binding var selection: Set<Note.ID>
  
  var body: some View {
    List(selection: $selection) {
      ForEach(notes) { note in
        NavigationLink(value: note) {
          NoteRowCell(note: note)
        }
      }
    }
  }

    init(sort: SortDescriptor<Note>, searchString: String, selection: Binding<Set<Note.ID>>) {
        _notes = Query(filter: #Predicate {
            if searchString.isEmpty {
                return true
            } else {
                return $0.content.localizedStandardContains(searchString)
            }
        }, sort: [sort])
        _selection = selection
    }
}

This is the ContentView:

struct ContentView: View {
@Environment(\.modelContext) private var modelContext

    @State private var sortOrder = SortDescriptor(\Note.creationDate, order: .reverse)
    @State private var isShowingSearch = false
    @State private var searchText = ""
    @State private var path = [Note]()
    @State private var selection = Set<Note.ID>()
  
    var body: some View {
      NavigationStack(path: $path) {
        NotesListView(
            sort: sortOrder,
            searchString: searchText,
            selection: $selection
        )
        .navigationDestination(for: Note.self) { note in
            NoteEditorView(note: note)
        }
        .toolbar {
           Button("Add Note") {
             let note = Note()
             modelContext.insert(note)
             path = [note]
           }
         }
         .searchable(
            text: $searchText,
            isPresented: $isShowingSearch,
            prompt: "Search"
        )
    }
}

This is the NoteEditor:

struct NoteEditor: View {
  @Bindable var note: Note // I guess this is the problem
  
  var body: some View {
    VStack {
      TextField("Note title", text: $note.title)

      Divider() 
      
      TextEditor(text: $note.content)
    }
    .padding(.horizontal, 25)
  }
}

Typing to this literally takes 125% CPU usage. I assume that is because I am writing directly to SwiftData. Some kind of delay saving will solve this I guess. I tried but it isn't working.

5
  • Show a minimal reproducible code that produces your issue, see: minimal code. Show the code where you call NoteEditor and what you pass to it, eg, is it coming from a @Query var ...? You could be correct with your comment @Bindable var note: Note // I guess this is the problem. Commented Jul 17 at 7:53
  • I have updated the question now you can clearly see how I am using the @Query. I hope you will help me to solve the issue 😄 Commented Jul 17 at 11:33
  • I voted to reopen this but if it isn't here is a way forward: Add local properties for the Note properties you are editing in the editor view like @State private var title: String = "" and then assign them in onAppear like title = note.title and then do the opposite in onDisappear, note.title = title and of course this should be done for all the properties. This way when you change your properties all changes will be local to the view and the edited Note object will only be changed when you leave the view which mean the @Query will only update itself once. Commented Jul 17 at 12:52
  • Lastly I used let instead of @Bindable var for the note property and that worked fine although it seems to work fine also without this change. And if it wasn't clear from my previous comment the 125% CPU usage you saw was from the query executing for basically every change (keystroke) in the editor view Commented Jul 17 at 12:53
  • Thanks for the help Joakim. This is working pretty nice. Now the only thing left is to handle an edge case. Imagine a user makes a new note and then type for a while and instead of going back it returns to the home and exit the app. Then after some time the app get suspended and when the user reopens the app, the previously created note has gone. .onDisappear is not for this kind of scenario I guess or maybe I am missing something Edit: I solved this .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in saveNote() } Commented Jul 17 at 14:07

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.