Fix background notification processing of CloudKit changes.

This commit is contained in:
Maurice Parker 2020-04-01 20:21:14 -05:00
parent 850d6b5623
commit ea78b5683d
5 changed files with 40 additions and 23 deletions

View File

@ -58,6 +58,8 @@ final class CloudKitAccountDelegate: AccountDelegate {
}
func receiveRemoteNotification(for account: Account, userInfo: [AnyHashable : Any], completion: @escaping () -> Void) {
os_log(.debug, log: log, "Processing remote notification...")
let group = DispatchGroup()
zones.forEach { zone in
@ -68,6 +70,7 @@ final class CloudKitAccountDelegate: AccountDelegate {
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done processing remote notification...")
completion()
}
}

View File

@ -48,14 +48,10 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate {
}
}
func cloudKitDidChange(records: [CKRecord]) {
// We don't batch process these records
func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void) {
completion(.success(()))
}
func cloudKitDidDelete(recordKeys: [CloudKitRecordKey]) {
// We don't batch process these records
}
func addOrUpdateWebFeed(_ record: CKRecord) {
guard let account = account,
let urlString = record[CloudKitAccountZone.CloudKitWebFeed.Fields.url] as? String,

View File

@ -31,7 +31,8 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate {
// Article downloads clean up old articles and statuses
}
func cloudKitDidChange(records: [CKRecord]) {
func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void) {
database.selectPendingReadStatusArticleIDs() { result in
switch result {
case .success(let pendingReadStatusArticleIDs):
@ -40,9 +41,10 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate {
switch result {
case .success(let pendingStarredStatusArticleIDs):
self.process(records: records,
self.process(records: changed,
pendingReadStatusArticleIDs: pendingReadStatusArticleIDs,
pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs)
pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs,
completion: completion)
case .failure(let error):
os_log(.error, log: self.log, "Error occurred geting pending starred records: %@", error.localizedDescription)
@ -56,15 +58,11 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate {
}
func cloudKitDidDelete(recordKeys: [CloudKitRecordKey]) {
// Article downloads clean up old articles and statuses
}
}
private extension CloudKitArticlesZoneDelegate {
func process(records: [CKRecord], pendingReadStatusArticleIDs: Set<String>, pendingStarredStatusArticleIDs: Set<String>) {
func process(records: [CKRecord], pendingReadStatusArticleIDs: Set<String>, pendingStarredStatusArticleIDs: Set<String>, completion: @escaping (Result<Void, Error>) -> Void) {
let receivedUnreadArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "0" }).map({ $0.externalID }))
let receivedReadArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "1" }).map({ $0.externalID }))
@ -76,10 +74,31 @@ private extension CloudKitArticlesZoneDelegate {
let updateableUnstarredArticleIDs = receivedUnstarredArticleIDs.subtracting(pendingStarredStatusArticleIDs)
let updateableStarredArticleIDs = receivedStarredArticleIDs.subtracting(pendingStarredStatusArticleIDs)
account?.markAsUnread(updateableUnreadArticleIDs)
account?.markAsRead(updateableReadArticleIDs)
account?.markAsUnstarred(updateableUnstarredArticleIDs)
account?.markAsStarred(updateableStarredArticleIDs)
let group = DispatchGroup()
group.enter()
account?.markAsUnread(updateableUnreadArticleIDs) { _ in
group.leave()
}
group.enter()
account?.markAsRead(updateableReadArticleIDs) { _ in
group.leave()
}
group.enter()
account?.markAsUnstarred(updateableUnstarredArticleIDs) { _ in
group.leave()
}
group.enter()
account?.markAsStarred(updateableStarredArticleIDs) { _ in
group.leave()
}
group.notify(queue: DispatchQueue.main) {
completion(.success(()))
}
}

View File

@ -19,8 +19,7 @@ enum CloudKitZoneError: Error {
protocol CloudKitZoneDelegate: class {
func cloudKitDidChange(record: CKRecord);
func cloudKitDidDelete(recordKey: CloudKitRecordKey)
func cloudKitDidChange(records: [CKRecord]);
func cloudKitDidDelete(recordKeys: [CloudKitRecordKey])
func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void);
}
typealias CloudKitRecordKey = (recordType: CKRecord.RecordType, recordID: CKRecord.ID)
@ -326,9 +325,7 @@ extension CloudKitZone {
case .success:
DispatchQueue.main.async {
self.refreshProgress?.completeTask()
self.delegate?.cloudKitDidChange(records: changedRecords)
self.delegate?.cloudKitDidDelete(recordKeys: deletedRecordKeys)
completion(.success(()))
self.delegate?.cloudKitDidModify(changed: changedRecords, deleted: deletedRecordKeys, completion: completion)
}
case .zoneNotFound:
self.createZoneRecord() { result in

View File

@ -112,7 +112,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
DispatchQueue.main.async {
self.resumeDatabaseProcessingIfNecessary()
AccountManager.shared.receiveRemoteNotification(userInfo: userInfo) {
self.suspendApplication()
completionHandler(.newData)
}
}