При извлечении основных данных в AppIntent происходит сбой, когда приложение работает в фоновом режиме
Я создаю ярлык AppIntent и хочу выполнить запросы на получение основных данных моего приложения, чтобы передать данные в ярлык.
Мой код
Основная обработка данных:
class HomesHandler: NSObject, ObservableObject {
static let shared = HomesHandler()
let objectContext = PersistenceController.shared.container.viewContext
func fetchAllHomes() -> [Home] {
let request: NSFetchRequest<Home> = Home.fetchRequest()
// PERFORM FETCH
do {
return try objectContext.fetch(request)
} catch let error {
print("Error fetching Homes: \(error.localizedDescription)")
return []
}
}
}
Код намерения приложения:
struct HomeIntentQuery: EntityPropertyQuery {
// Populates the list when the user taps on a parameter that accepts a Home.
func suggestedEntities() async throws -> [HomeIntentEntity] {
// Fetch All Homes
// Sorted by non-archived first
let allHomes = HomesHandler.shared.fetchAllHomes().sorted(by: { !$0.isArchived && $1.isArchived })
// Map Core Data to AppEntity
return allHomes.map { home in
HomeIntentEntity(id: home.id,
title: home.wrappedTitle,
isArchived: home.isArchived)
}
}
// …
Объект намерения для моста базовых данных:
struct HomeIntentEntity: AppEntity, Identifiable {
// Required to conform to Identifiable
var id: UUID
// Properties mirrored from Core Data
@Property(title: "Title") var title: String
@Property(title: "Is Archived") var isArchived: Bool
// …
}
Основной контроллер постоянства данных:
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
// An initializer to load Core Data,
// optionally able to use an in-memory store.
init(inMemory: Bool = false) {
// Access actual Core Data file
container = NSPersistentContainer(name: "MeterStats")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Core Data Loading Error: \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
}
}
Проблема
У меня проблема в том, что код аварийно завершает работу с EXC_BREAKPOINT каждый раз, когда приложение работает в фоновом режиме. После закрытия приложения запрос на выборку работает нормально. Как это может быть?
Я уже пытался обернутьdo try objectContext.fetch(request)
вobjectContext.performAndWait
. Однако это приводит к сбою внутри.sorted(by:)
при попытке доступа.isArchived
Странно то, что это прекрасно работает в замечательном примере GitHub от Алекса Хэя. Он использует тот же код для выполнения запроса на выборку , что и код AppIntent .
Итак, как мне правильно обрабатывать запросы на выборку, которые выполняются внутри AppIntents?
1 ответ
Проблема заключалась в том, что по какой-то причине запрос на выборку выполнялся вне основного потока приложения. Однако не знаю, почему в примере с Booky это работает без него.
Чтобы решить эту проблему, я теперь используюtry context.performAndWait {}
действие для выполнения запроса на выборку внутри. Важно отметить, что необходимо выполнить сопоставление основного объекта данных с пользовательским внутриperformAndWait
! В противном случае это приведет к сбою при созданииAppEntity
объект.
struct HomeIntentQuery: EntityPropertyQuery {
// Populates the list when the user taps on a parameter that accepts a Home.
func suggestedEntities() async throws -> [HomeIntentEntity] {
// Fetch All Homes
// Sorted by non-archived first
let context = PersistenceController.shared.container.viewContext
let request: NSFetchRequest<Home> = Home.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \Home.isArchived, ascending: true)]
var allHomes: [HomeIntentEntity] = []
try context.performAndWait {
do {
allHomes = try context.fetch(request).map { home in
// Map Core Data to AppEntity
HomeIntentEntity(id: home.id, title: home.wrappedTitle, isArchived: home.isArchived)
}
} catch {
throw error
}
}
return allHomes
}
// …
}