NSManagedObjectContext Async/Await выполнить (расписание:_:)» доступно только в iOS 15.0 или новее.

Я работаю над приложением, которое по-прежнему поддерживает iOS 13, и мне нужно получить некоторые данные с помощью CoreData.

Вот как я обычно это делаю

      context.perform({
  let results = try context.fetch(request)
})

Теперь, когда Xcode 13 и async/await доступны обратно в iOS 13, я получаю ошибку компилятора.

'выполнить (расписание:_:)' доступно только в iOS 15.0 или новее

Переход к определению показывает следующий новый API в CoreData

      @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension NSManagedObjectContext {

    public func performAndWait<T>(_ block: () throws -> T) rethrows -> T

    public func perform<T>(schedule: NSManagedObjectContext.ScheduledTaskType = .immediate, _ block: @escaping () throws -> T) async rethrows -> T
}

При комментировании кода в блоке он вместо этого переходит к старому API в CoreData/NSManagedObjectContext.

      /* asynchronously performs the block on the context's queue.  Encapsulates an autorelease pool and a call to processPendingChanges */
@available(iOS 5.0, *)
open func perform(_ block: @escaping () -> Void)

Почему компилятор выбирает новый вариант perform и как я могу заставить его использовать более старую неасинхронную версию?

Изменить: Вот минимальный пример проекта, демонстрирующий проблему: https://github.com/iv-mexx/CoreDataRepro .

1 ответ

Благодаря @Cy-4AH я понял это!

Проблема была в том, что я делал все, включая context.performв одном большом do / catchблокировать

      do {
    ...
    context.perform({
      let results = try context.fetch(request)
    })
    ...
} catch { 
    ...
}

Новый метод расширения для теперь помечен как rethrowsтогда как старый не был, поэтому тот факт, что в блоке выполнения был метод броска, означал, что компилятор выбрал повторный бросок, который доступен только на iOS>= 15.

@Cy-4AH предложил использовать try?вместо tryкоторый работает, потому что ошибка ловится прямо там, не заставляя rethrowingметод, который будет использоваться.

Другим решением является перемещение do/catchвнутри perform:

      context.perform({
  do {
    let results = try context.fetch(request)
  } catch { 
    ...
  }
})
Другие вопросы по тегам