1

I've followed along the Apple Developer Code-Along videos (https://developer.apple.com/news/?id=yv6so7ie) as well as looked at this repo with different Widget types (https://github.com/pawello2222/WidgetExamples) in search on how to populate a dynamic intent with items from Core Data.

My question is: How can I used the saved Core Data objects from the user to have them as "filters" or options in widget settings?

My Core Data model is called Favourite and it is a Class Definition CodeGen file.

I have added the Intent target to my project and can get it to appear in the Widget settings, but when I tap in to "Choose" the list is empty. However, in my Core Data there are 3 saved items.

I have tried doing simple things like print(CoreDM.shared.getAllFavourites()) to see if I am even retrieving them all, but not listing in the settings, but the console prints out:

<NextDeparturesIntent: 0x283490bd0> {
    favourite = <null>;
}

At this point I'm stuck on understanding on how I can get my Favourites visible and then usable. It seems everything else is hooked up and working or ready but the retrieval.

I have also tried re-adding into the Info.plist of the intent the IntentSupported of the intent's name: NextDeparturesIntentHandling:

but that had no success.


Files

Core Data Model - Favourite - FavouritesCDModel

In my Core Data model I have more options but for this example:

  • UUID
  • beginName
  • finishName

Widget Intent - NextDepartures.intentdefinition

This is what has been set up as followed by Apple's Code Along videos:

app-name-intent - IntentHandler.swift

import Intents

class IntentHandler: INExtension, NextDeparturesIntentHandling {
  let coreDM = CoreDataManager.shared

  func provideFavouriteOptionsCollection(
    for intent: NextDeparturesIntent,
    with completion: @escaping (INObjectCollection<FavouriteRoutes>?, Error?) -> Void
  ) {

    dump( coreDM.getAllFavourites() ) // <--- debug line

    let favouriteRoutes = coreDM.getAllFavourites().map {
      FavouriteRoutes(identifier: $0.uniqueId, display: $0.departingStopName!)
    }

    let collection = INObjectCollection(items: favouriteRoutes)
    completion(collection, nil)
  }

  override func handler(for intent: INIntent) -> Any {
    return self
  }
}

CoreDataManager

import CoreData

final class CoreDataManager {

  static let shared = CoreDataManager()
  private init() {}

  private let persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "FavouritesCDModel")
    container.loadPersistentStores(completionHandler: { description, error in
      if let error = error as NSError? {
        fatalError("Core Data Store failed \(error.localizedDescription)")
      }
    })
    return container
  }()

  var managedObjectContext: NSManagedObjectContext {
    persistentContainer.viewContext
  }

  func getAllFavourites() -> [Favourite] {
    let fetchRequest: NSFetchRequest<Favourite> = Favourite.fetchRequest()
    do {
      return try managedObjectContext.fetch(fetchRequest)
    } catch {
      return []
    }
  }
}
4
  • What is your question? This sounds like a wish/todo list but we have nothing to go on to help you. Welcome to SO - Please take the tour and read How to Ask to improve, edit and format your questions. Without a Minimal Reproducible Example it is impossible to help you troubleshoot. Commented Feb 15, 2022 at 15:29
  • Widgets code-along and Core Data and App extensions: Sharing a single database may be helpful in your journey. Commented Feb 15, 2022 at 15:31
  • @loremipsum I've updated it so it hopefully makes more sense of the question I am after: How can I list all CoreData items from a model as the Widgets Intents? Commented Feb 15, 2022 at 23:18
  • Go through the code along give it a try and if you have a specific issue we can help. 99% of what you need is in those too links. This isn’t the place to just ask for code we can help when you have a specific implementation issue. Commented Feb 15, 2022 at 23:23

1 Answer 1

2

I didn't realise that the app, widget, and other targets are all sandboxed.

I incorrectly assumed everything within the same app ecosystem would be allowed access to the same items.

In order to get the above code to work is adding the file to the App Groups and FileManager.


CoreDataManager

Inside the persistentContainer add in the storeURL and descriptions:

let storeURL = FileManager.appGroupContainerURL.appendingPathComponent("COREDATAFILE.sqlite")
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeURL)]

FileManager+Ext

Create a FileManager extension for the container url:

extension FileManager {
  static let appGroupContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.domain.app")!
}

Info.plist

Make sure that the Info.plist files have access to the app group

Signing and Capabilities

Make sure you add the App Groups capability to each target that needs it, and add it in App Store Connect

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

1 Comment

Glad you got it working, that was the second link I gave you.

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.