Как вызвать WidgetCenter.shared.reloadAllTimelines() при изменении основных данных в CloudKit?

#swift #core-data #swiftui #cloudkit #widgetkit

#swift #основные данные #swiftui #cloudkit #widgetkit

Вопрос:

У меня есть приложение, которое использует основные данные с CloudKit. Изменения синхронизируются между устройствами. Основной целевой объект имеет возможность фоновых режимов с проверкой Remote notifications , возможность iCloud проверяется с помощью служб, настроенных на CloudKit, и правильного контейнера в контейнерах.

Как я могу реагировать в коде на изменения, удаление и добавление записей? Мне нужно позвонить WidgetCenter.shared.reloadAllTimelines() , когда основные данные в CloudKit изменятся, чтобы обновить виджет рабочего стола iOS 14.

Моя цель — заставить это работать: я изменяю / добавляю / удаляю запись в icloud.developer.apple.com или другое устройство, и WidgetCenter.shared.reloadAllTimelines() вызывается для отображения правильных данных в виджете. Приложение может находиться в фоновом режиме или на переднем плане.

От AppDelegate.swift :

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Register for Remote Notifications
    application.registerForRemoteNotifications()
    
    return true
}
  

Кроме того, замеченные сообщения в журнале вывода:

CoreData: debug: CoreData CloudKit: -[NSCloudKitMirroringDelegate remoteStoreDidChange:]_block_invoke(2138): <NSCloudKitMirroringDelegate: 0x281818d00> — Игнорирование уведомления об удаленных изменениях, поскольку экспортер уже перехватил эту транзакцию: 64/64 — < NSSQLCore: 0x100b09440> (URL: файл:///var/мобильный/Containers/Data/Application/F83C68DA-7C36-42CC-926D-7C721C679579/Library/Application Support/AppTitle.sqlite)

Ответ №1:

Если вы хотите подписаться на удаленные уведомления Core Data, вы можете использовать onReceive :

 struct WidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        Text(entry.date, style: .time)
            .onReceive(NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange)) { _ in
                // make sure you don't call this too often
                WidgetCenter.shared.reloadAllTimelines()
            }
    }
}
  

Просто убедитесь, что вы не вызываете reloadAllTimelines() слишком часто — вероятно, для вашего виджета доступно ограниченное количество обновлений.

Комментарии:

1. Вы действительно уверены, что это будет работать так, как задумано? Насколько я понимаю, как только виджет завершает возврат временной шкалы getTimeline , расширение виджета прекращается. Таким образом, этот прослушиватель сможет прослушивать только в течение нескольких секунд жизни расширения. Из того, что я прочитал в документах, такое прослушивание может быть выполнено только из приложения: developer.apple.com/documentation/widgetkit /. … Видя, что за это проголосовали, кому-нибудь действительно удалось заставить это работать надежно?

2. Я также подозреваю, что это не будет работать как есть. Я думаю, что если бы у вас был этот код в вашем основном приложении, он бы работал. И пока приложение находится на переднем плане, нет ограничений на количество вызовов reloadAllTimelines() (конечно, вы хотите, чтобы это работало и в фоновом режиме, но просто уточняю)