Search code examples
swiftuiios15

SwiftUI Save ManagedObjectContext after Toggle


In my SwiftUI / iOS 15+ app, I have a toolbar displaying a button which is meant to toggle the "bookmarked" property of an "item" object. The item is passed in as a Binding, as shown here:

import SwiftUI

struct PageViewToolbar: ToolbarContent {
    @Environment(\.managedObjectContext) var context

    @Binding var item: Item //CoreData ManagedObject
    
    var body: some ToolbarContent {
        ToolbarItem(placement: .automatic) {
            Toggle(isOn: self.$item.bookmarked) {
                Image(systemName: "bookmark")
                    .symbolVariant(self.item.bookmarked ? .fill : .none)
            } //Toggle
            .toggleStyle(.button)
        } //ToolbarItem
    } //body
} //PageViewToolbar

The button is toggling and the bookmarked property on the item is being set accordingly, but item is a CoreData ManagedObject and so I need to trigger a context save whenever the property is changed. Is there a way to attach that logic to the Toggle button?


Solution

  • First of all item is reference type so you must use @ObservedObject rather than @Binding to get notified about changes. Fortunately NSManagedObject conforms to ObservableObject by default.

    Then add the .onChange modifier to save the context when bookmarked has changed.

    struct PageViewToolbar: ToolbarContent {
        @Environment(\.managedObjectContext) var context
    
        @ObservedObject var item: Item 
        
        var body: some ToolbarContent {
            ToolbarItem(placement: .automatic) {
                Toggle(isOn: $item.bookmarked) {
                    Image(systemName: "bookmark")
                        .symbolVariant(item.bookmarked ? .fill : .none)
                } //Toggle
                .toggleStyle(.button)
                .onChange(of: item.bookmarked) { _ in
                    try? context.save()
                 }
            } //ToolbarItem
        } //body
    } //PageViewToolbar