Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically reflect CoreData+iCloud Changes in SwiftUI view?

🤓 So...I have an app with StoreData and iCloud enabled. My data is syncing between the devices but I don't ge the behaviour I want when it comes to reflecting the changes in the UI.

The behaviour I want: When a user has my app open on two devices (A & B) and makes a change one one (A) of them I want the change to automatically reflect in the second (B) device UI within some reasonable time.

enter image description here

The behaviour I currently have: When the user makes changes on one device (A) nothing ever happens on the other (B)...until I minimise and maximise the app on the second device (B) (Not restarting...just minimising).

enter image description here

🤔 My thought are that the app won't receive the changes (iCloud won't sync) until some action is triggered when minimising and reopening the app.

🥺 But I don't know. According to Syncing a Core Data Store with CloudKit syncing and notifying other devices should happened automatically. And I think my View should be hooked up correctly as it will change instantly when making local changes to data in the CoreData database.

My SwiftUI view pretty much looks like this:

import SwiftUI
import CloudKit
import Foundation

struct MyView: View {
    @FetchRequest(fetchRequest: Entity.fetchRequest() as! NSFetchRequest<Entity>) var entities: FetchedResults<Entity>

    var body: some View {
        List {
            ForEach(entities, id: \.id) { e in
                Text("\(e.title)")
            }
        }
    }
}

public class Entity: NSManagedObject {
    @NSManaged public var id: UUID?
    @NSManaged public var title: String
}

Any Help is much appreciated! (Let me know if I need to provide additional information.)

like image 984
iSebbeYT Avatar asked Mar 04 '20 18:03

iSebbeYT


People also ask

How to implement core data in SwiftUI with contentview?

But make sure to use SwiftUI as the “Interface” mode and SwiftUI App as the “Life Cycle” mode. Also, make sure that you check the “Use Core Data” box. This will automatically set up the initial Core Data implementation for our app! Make sure you “reset” the ContentView by removing the generated code from it since we won’t need it for our app.

How to create an app with SwiftUI in Xcode 12?

To get started, open Xcode 12 and create a new “App” under “Multiplatform” or “iOS”. You can name your project however you want, for instance, “PizzaRestaurant”. But make sure to use SwiftUI as the “Interface” mode and SwiftUI App as the “Life Cycle” mode. Also, make sure that you check the “Use Core Data” box.

How to create a single view app with core data in iOS?

The first step is to create a new project based on the Single View App template. Next, name the project, select your team name, and select “Use Core Data” and “Use CloudKit” checkboxes. Xcode generates some code in the AppDelegate.swift file to initialize the Core Data stack with this new class since iOS 13: NSPersistentCloudKitContainer.

How do I create a single view project in SwiftUI?

Select a Single View template and check the Core Data and Cloudkit boxes on the next screen and choose SwiftUI as the User Interface. Once you’re done filling in other fields, proceed to creating a project. Good news is half of the job is already done for you.


1 Answers

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentCloudKitContainer = {

    let container = NSPersistentCloudKitContainer(name: "ComCloudSync")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

Try adding the following code (change "ComCloudSync" to your appName):

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentCloudKitContainer = {

    let container = NSPersistentCloudKitContainer(name: "ComCloudSync")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })

    container.viewContext.automaticallyMergesChangesFromParent = true
    container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy

  return container
}()
like image 136
Sir Spiff Avatar answered Sep 22 '22 03:09

Sir Spiff