18

I want to display data fetched from Core Data in a widget. But @FetchRequest doesn’t work on widgets.

As I understand, we have to create an app group and make a shared persistent container.

What I want to know is how to read (fetch) data on widgets from that shared persistent container or simply, how to display data fetched from Core Data in widgets.

pawello2222
  • 46,897
  • 22
  • 145
  • 209
umayanga
  • 2,254
  • 3
  • 15
  • 26

2 Answers2

33

First you need to create an AppGroup which will be used to create a Core Data Persistent Container (here is a good explanation how to do it)

Then you need to create your own CoreData stack (an example can be found when you create a new empty project with CoreData enabled).

Assuming you have already created your Core Data model (here called DataModel), you now need to set the container url to your custom shared container location:

let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: <your_app_group>)!
let storeURL = containerURL.appendingPathComponent("DataModel.sqlite")
let description = NSPersistentStoreDescription(url: storeURL)

let container = NSPersistentContainer(name: "DataModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { ... }

Now you can get the managedObjectContext from your shared Persistent Container:

let moc = CoreDataStack.shared.managedObjectContext

and perform a fetch request with it (more information here)

let predicate = NSPredicate(format: "attribute1 == %@", "test")
let request = NSFetchRequest<SomeItem>(entityName: "SomeItem")
let result = try moc.fetch(request)

Apart from all the links above I recommend you also read this tutorial about Core Data:


Here is a GitHub repository with different Widget examples including the Core Data Widget.

pawello2222
  • 46,897
  • 22
  • 145
  • 209
  • 5
    Thanks pawello2222 for this detailed answer. To elaborate on pawello2222's answer, if you use CloudKit, replace `NSPersistentContainer ` with `NSPersistentCloudKitContainer` (even on the newly created CoreData stack) – umayanga Sep 19 '20 at 02:04
  • Hey pawello2222, thanks so much for the answer and for sharing that GitHub repository. I've followed the code in that repository and my widget refreshes completely fine. But I lost all the data on my old managedObjectContext. Can you please tell me how to transfer the data on the old managedObjectContext to the new managedObjectContext in the CoreData stack? – Alex Oct 31 '20 at 16:45
  • 1
    @Alex This is because you create a new NSPersistentContainer which is located in a different place than your old one. You need to move/copy your old container to the new location. This post might help you: [iOS 11+ How to migrate existing Core Data to Shared App Group for use in extension?](https://stackoverflow.com/q/52191523/8697793) – pawello2222 Oct 31 '20 at 17:10
  • Does this also work with custom Core Data classes? – Luca Jan 20 '21 at 20:31
  • @Luca This doesn't change any Core Data behaviour, just the container location. Everything else is like in any *standard* app. – pawello2222 Jan 20 '21 at 20:34
  • So, if i have some Core Data custom classes with custom methods etc. i need them to target my widget or not? – Luca Jan 20 '21 at 21:12
  • 1
    @Luca You need to make sure that all what is needed in the widget is added to the widget target. If you plan to use Core Data and custom classes in the widget, you need to add them all to the widget target. – pawello2222 Jan 20 '21 at 22:04
  • I followed the same steps above but the app crashed, if anyone can help the issue link: https://stackoverflow.com/questions/73820233/swiftui-crash-in-main-after-added-app-groups-capability-with-coredata?noredirect=1#comment130352047_73820233 – Ammar Ahmad Sep 23 '22 at 04:44
2

For people who did all the work above, and finally can get the connection to your Core Data (e.g. you can get the count of request), but can't fetch the request, is mostly because that the entity you're fetching contains transformable type, and for some reason this error occurred: Cannot decode object of class, try fix this.

Dary
  • 21
  • 1
  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. - [From Review](/review/late-answers/32923536) – Mohamed Elkassas Oct 17 '22 at 13:46
  • They dont have a new question, they just gave additional information that may help someone for whom the accepted answer did not work. Please go be pedantic somewhere else. – charelf Mar 05 '23 at 14:37