4

I have an app that uses Core Data with CloudKit. Changes are synced between devices. Main target has Background Modes capability with checked Remote notifications, iCloud capability is checked with Services set to CloudKit and correct container in Containers checked.

How can I react in code to changes, deleting, and addition of records? I need to call WidgetCenter.shared.reloadAllTimelines() when Core Data in CloudKit changes to update iOS 14 homescreen widget.

My goal is to get this working: I change/add/delete record on icloud.developer.apple.com or another device, and WidgetCenter.shared.reloadAllTimelines() called to display correct data in widget. App may be in background or foreground.

From AppDelegate.swift:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Register for Remote Notifications
    application.registerForRemoteNotifications()
    
    return true
}

Also, noticed messages in output log:

CoreData: debug: CoreData+CloudKit: -[NSCloudKitMirroringDelegate remoteStoreDidChange:]_block_invoke(2138): <NSCloudKitMirroringDelegate: 0x281818d00> - Ignoring remote change notification because the exporter has already caught up to this transaction: 64 / 64 - <NSSQLCore: 0x100b09440> (URL: file:///var/mobile/Containers/Data/Application/F83C68DA-7C36-42CC-926D-7C721C679579/Library/Application%20Support/AppTitle.sqlite)

1 Answer 1

6

If you want to subscribe to Core Data remote notifications you can use onReceive:

struct WidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        Text(entry.date, style: .time)
            .onReceive(NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange)) { _ in
                // make sure you don't call this too often
                WidgetCenter.shared.reloadAllTimelines()
            }
    }
}

Just make sure you don't call reloadAllTimelines() too often - there likely is a limited number of updates available to your widget.

Sign up to request clarification or add additional context in comments.

2 Comments

Are you really sure this will work as intended? From my understanding, once a widget is done returning a Timeline from getTimeline, the widget extension gets terminated. So this listener would only be able to listen during the few seconds the extension lives. From what I've read in the docs, this kind of listening could only be done from the app: developer.apple.com/documentation/widgetkit/…. Seeing this upvoted, does anyone has actually managed to get this working reliably?
I also suspect that this would not work as is. I think if you had this code in your main app it would work. And as long as the app is in the foreground there is no limit on how many times you call reloadAllTimelines() (of course you want this to work in the background too, but just clarifying)

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.