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

View File

@ -48,12 +48,8 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate {
} }
} }
func cloudKitDidChange(records: [CKRecord]) { func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void) {
// We don't batch process these records completion(.success(()))
}
func cloudKitDidDelete(recordKeys: [CloudKitRecordKey]) {
// We don't batch process these records
} }
func addOrUpdateWebFeed(_ record: CKRecord) { func addOrUpdateWebFeed(_ record: CKRecord) {

View File

@ -31,7 +31,8 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate {
// Article downloads clean up old articles and statuses // 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 database.selectPendingReadStatusArticleIDs() { result in
switch result { switch result {
case .success(let pendingReadStatusArticleIDs): case .success(let pendingReadStatusArticleIDs):
@ -40,9 +41,10 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate {
switch result { switch result {
case .success(let pendingStarredStatusArticleIDs): case .success(let pendingStarredStatusArticleIDs):
self.process(records: records, self.process(records: changed,
pendingReadStatusArticleIDs: pendingReadStatusArticleIDs, pendingReadStatusArticleIDs: pendingReadStatusArticleIDs,
pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs) pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs,
completion: completion)
case .failure(let error): case .failure(let error):
os_log(.error, log: self.log, "Error occurred geting pending starred records: %@", error.localizedDescription) 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 { 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 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 })) 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 updateableUnstarredArticleIDs = receivedUnstarredArticleIDs.subtracting(pendingStarredStatusArticleIDs)
let updateableStarredArticleIDs = receivedStarredArticleIDs.subtracting(pendingStarredStatusArticleIDs) let updateableStarredArticleIDs = receivedStarredArticleIDs.subtracting(pendingStarredStatusArticleIDs)
account?.markAsUnread(updateableUnreadArticleIDs) let group = DispatchGroup()
account?.markAsRead(updateableReadArticleIDs)
account?.markAsUnstarred(updateableUnstarredArticleIDs) group.enter()
account?.markAsStarred(updateableStarredArticleIDs) 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 { protocol CloudKitZoneDelegate: class {
func cloudKitDidChange(record: CKRecord); func cloudKitDidChange(record: CKRecord);
func cloudKitDidDelete(recordKey: CloudKitRecordKey) func cloudKitDidDelete(recordKey: CloudKitRecordKey)
func cloudKitDidChange(records: [CKRecord]); func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result<Void, Error>) -> Void);
func cloudKitDidDelete(recordKeys: [CloudKitRecordKey])
} }
typealias CloudKitRecordKey = (recordType: CKRecord.RecordType, recordID: CKRecord.ID) typealias CloudKitRecordKey = (recordType: CKRecord.RecordType, recordID: CKRecord.ID)
@ -326,9 +325,7 @@ extension CloudKitZone {
case .success: case .success:
DispatchQueue.main.async { DispatchQueue.main.async {
self.refreshProgress?.completeTask() self.refreshProgress?.completeTask()
self.delegate?.cloudKitDidChange(records: changedRecords) self.delegate?.cloudKitDidModify(changed: changedRecords, deleted: deletedRecordKeys, completion: completion)
self.delegate?.cloudKitDidDelete(recordKeys: deletedRecordKeys)
completion(.success(()))
} }
case .zoneNotFound: case .zoneNotFound:
self.createZoneRecord() { result in 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) { func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
DispatchQueue.main.async { DispatchQueue.main.async {
self.resumeDatabaseProcessingIfNecessary()
AccountManager.shared.receiveRemoteNotification(userInfo: userInfo) { AccountManager.shared.receiveRemoteNotification(userInfo: userInfo) {
self.suspendApplication()
completionHandler(.newData) completionHandler(.newData)
} }
} }