При извлечении основных данных в 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
    }

    // …
}
Другие вопросы по тегам