在 SwiftUI 中使用 CoreData 作为动态 Widget Intents

Using CoreData as dynamic Widget Intents in SwiftUI

我关注了 Apple Developer Code-Along 视频 (https://developer.apple.com/news/?id=yv6so7ie) as well as looked at this repo with different Widget types (https://github.com/pawello2222/WidgetExamples) 以搜索如何使用 Core Data 中的项目填充动态意图。

我的问题是:我如何使用用户保存的核心数据objects将它们作为“过滤器”或小部件设置中的选项?

我的核心数据模型称为 Favourite,它是一个 Class 定义 CodeGen 文件。

我已经将 Intent 目标添加到我的项目中,并且可以让它出现在小部件设置中,但是当我点击“选择”时,列表是空的。然而,在我的核心数据中有 3 个保存的项目。

我尝试做一些简单的事情,比如 print(CoreDM.shared.getAllFavourites()) 看看我是否能全部检索到它们,但没有在设置中列出,但控制台打印出来:

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

在这一点上,我一直在了解如何让我的收藏夹可见然后可用。似乎其他一切都已连接并工作或准备就绪,但检索。

我也试过 re-adding 进入意图的 Info.plist 意图名称的 IntentSupported:NextDeparturesIntentHandling:

但是没有成功。


文件

核心数据模型 - Favourite - FavouritesCDModel

在我的核心数据模型中,我有更多选项,但对于这个例子:

小部件意图 - NextDepartures.intentdefinition

这是按照 Apple 的 Code Along 视频设置的:

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: [=11=].uniqueId, display: [=11=].departingStopName!)
    }

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

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

核心数据管理器

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 []
    }
  }
}

我没有意识到应用程序、小部件和其他目标都被沙盒化了。

我错误地假设同一应用生态系统中的所有内容都将被允许访问相同的项目。

为了使上述代码正常工作,将文件添加到 App GroupsFileManager


核心数据管理器

persistentContainer 中添加 storeURL 和描述:

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

文件管理器+Ext

为容器创建 FileManager 扩展 url:

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

Info.plist

确保 Info.plist 文件有权访问应用程序组

签名和能力

确保将 App Groups 功能添加到需要它的每个目标,并将其添加到 App Store Connect