From 8d5f56c7ee84e7f17684c00e99cbcc97997fedc8 Mon Sep 17 00:00:00 2001 From: deeje Date: Wed, 26 Jan 2022 12:55:36 -0800 Subject: [PATCH 1/6] fix for CloudKit error 3, not online when using cellular qualityOfService = .userInitiated via https://stackoverflow.com/questions/34189458/cloudkit-ckdatabaseoperation-not-working-on-cellular --- README.md | 4 ++-- .../FetchPublicSubscriptionsOperation.swift | 2 +- Source/Classes/Pull/PullChangesOperation.swift | 8 ++++---- Source/Classes/Pull/PullOperation.swift | 2 +- Source/Classes/Pull/PullRecordOperation.swift | 2 +- .../SubOperations/FetchRecordZoneChangesOperation.swift | 4 ++-- .../Pull/SubOperations/PurgeLocalDatabaseOperation.swift | 2 +- Source/Classes/Push/PushOperationQueue.swift | 2 +- Source/Classes/Setup/CreateCloudCoreZoneOperation.swift | 3 ++- Source/Classes/Setup/PushAllLocalDataOperation.swift | 2 +- Source/Classes/Setup/SetupOperation.swift | 2 +- Source/Classes/Setup/SubscribeOperation.swift | 6 +++--- 12 files changed, 20 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 546b0ee..d5c06f5 100755 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ CloudCore now has built-in support for CloudKit Sharing. There are several addi func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) { let acceptShareOperation = CKAcceptSharesOperation(shareMetadatas: [cloudKitShareMetadata]) - acceptShareOperation.qualityOfService = .userInteractive + acceptShareOperation.qualityOfService = .userInitiated acceptShareOperation.perShareCompletionBlock = { meta, share, error in CloudCore.pull(rootRecordID: meta.rootRecordID, container: self.persistentContainer, error: nil) { } } @@ -198,7 +198,7 @@ OR func application(_ application: UIApplication, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) { let acceptShareOperation = CKAcceptSharesOperation(shareMetadatas: [cloudKitShareMetadata]) - acceptShareOperation.qualityOfService = .userInteractive + acceptShareOperation.qualityOfService = .userInitiated acceptShareOperation.perShareCompletionBlock = { meta, share, error in CloudCore.pull(rootRecordID: meta.rootRecordID, container: self.persistentContainer, error: nil) { } } diff --git a/Source/Classes/Pull/PublicSubscriptions/FetchPublicSubscriptionsOperation.swift b/Source/Classes/Pull/PublicSubscriptions/FetchPublicSubscriptionsOperation.swift index ebe055d..e7767ef 100644 --- a/Source/Classes/Pull/PublicSubscriptions/FetchPublicSubscriptionsOperation.swift +++ b/Source/Classes/Pull/PublicSubscriptions/FetchPublicSubscriptionsOperation.swift @@ -20,7 +20,7 @@ class FetchPublicSubscriptionsOperation: AsynchronousOperation { super.init() name = "FetchPublicSubscriptionsOperation" - qualityOfService = .userInteractive + qualityOfService = .userInitiated } override func main() { diff --git a/Source/Classes/Pull/PullChangesOperation.swift b/Source/Classes/Pull/PullChangesOperation.swift index 1f190b9..a4b8cb3 100644 --- a/Source/Classes/Pull/PullChangesOperation.swift +++ b/Source/Classes/Pull/PullChangesOperation.swift @@ -65,7 +65,7 @@ public class PullChangesOperation: PullOperation { let changedRecordIDs: NSMutableSet = [] let deletedRecordIDs: NSMutableSet = [] let fetchNotificationChanges = CKFetchNotificationChangesOperation(previousServerChangeToken: databaseChangeToken) - fetchNotificationChanges.qualityOfService = .userInteractive + fetchNotificationChanges.qualityOfService = .userInitiated fetchNotificationChanges.notificationChangedBlock = { innerNotification in if let innerQueryNotification = innerNotification as? CKQueryNotification { if innerQueryNotification.queryNotificationReason == .recordDeleted { @@ -80,7 +80,7 @@ public class PullChangesOperation: PullOperation { let allChangedRecordIDs = changedRecordIDs.allObjects as! [CKRecord.ID] let fetchRecords = CKFetchRecordsOperation(recordIDs: allChangedRecordIDs) fetchRecords.database = CloudCore.config.container.publicCloudDatabase - fetchRecords.qualityOfService = .userInteractive + fetchRecords.qualityOfService = .userInitiated fetchRecords.perRecordCompletionBlock = { record, recordID, error in if error == nil { self.addConvertRecordOperation(record: record!, context: backgroundContext) @@ -111,7 +111,7 @@ public class PullChangesOperation: PullOperation { let fetchDatabaseChanges = CKFetchDatabaseChangesOperation(previousServerChangeToken: databaseChangeToken) fetchDatabaseChanges.database = database - fetchDatabaseChanges.qualityOfService = .userInteractive + fetchDatabaseChanges.qualityOfService = .userInitiated fetchDatabaseChanges.recordZoneWithIDChangedBlock = { recordZoneID in changedZoneIDs.append(recordZoneID) } @@ -173,7 +173,7 @@ public class PullChangesOperation: PullOperation { if recordZoneIDs.isEmpty { return } let recordZoneChangesOperation = FetchRecordZoneChangesOperation(from: database, recordZoneIDs: recordZoneIDs, tokens: tokens) - recordZoneChangesOperation.qualityOfService = .userInteractive + recordZoneChangesOperation.qualityOfService = .userInitiated recordZoneChangesOperation.recordChangedBlock = { self.addConvertRecordOperation(record: $0, context: context) } diff --git a/Source/Classes/Pull/PullOperation.swift b/Source/Classes/Pull/PullOperation.swift index 1bd52bd..063d59b 100644 --- a/Source/Classes/Pull/PullOperation.swift +++ b/Source/Classes/Pull/PullOperation.swift @@ -24,7 +24,7 @@ public class PullOperation: Operation { super.init() - qualityOfService = .userInteractive + qualityOfService = .userInitiated queue.name = "PullQueue" queue.maxConcurrentOperationCount = 1 diff --git a/Source/Classes/Pull/PullRecordOperation.swift b/Source/Classes/Pull/PullRecordOperation.swift index 2617f04..fae1af7 100644 --- a/Source/Classes/Pull/PullRecordOperation.swift +++ b/Source/Classes/Pull/PullRecordOperation.swift @@ -63,7 +63,7 @@ public class PullRecordOperation: PullOperation { private func addFetchRecordsOp(recordIDs: [CKRecord.ID], backgroundContext: NSManagedObjectContext) { let fetchRecords = CKFetchRecordsOperation(recordIDs: recordIDs) fetchRecords.database = database - fetchRecords.qualityOfService = .userInteractive + fetchRecords.qualityOfService = .userInitiated fetchRecords.perRecordCompletionBlock = { record, recordID, error in if let record = record { self.fetchedRecordIDs.append(recordID!) diff --git a/Source/Classes/Pull/SubOperations/FetchRecordZoneChangesOperation.swift b/Source/Classes/Pull/SubOperations/FetchRecordZoneChangesOperation.swift index 39ceded..3fdd60d 100644 --- a/Source/Classes/Pull/SubOperations/FetchRecordZoneChangesOperation.swift +++ b/Source/Classes/Pull/SubOperations/FetchRecordZoneChangesOperation.swift @@ -38,7 +38,7 @@ class FetchRecordZoneChangesOperation: Operation { super.init() name = "FetchRecordZoneChangesOperation" - qualityOfService = .userInteractive + qualityOfService = .userInitiated } override func main() { @@ -90,7 +90,7 @@ class FetchRecordZoneChangesOperation: Operation { } fetchRecordZoneChanges.database = self.database - fetchRecordZoneChanges.qualityOfService = .userInteractive + fetchRecordZoneChanges.qualityOfService = .userInitiated return fetchRecordZoneChanges } diff --git a/Source/Classes/Pull/SubOperations/PurgeLocalDatabaseOperation.swift b/Source/Classes/Pull/SubOperations/PurgeLocalDatabaseOperation.swift index cb04c79..92cf3b2 100644 --- a/Source/Classes/Pull/SubOperations/PurgeLocalDatabaseOperation.swift +++ b/Source/Classes/Pull/SubOperations/PurgeLocalDatabaseOperation.swift @@ -21,7 +21,7 @@ class PurgeLocalDatabaseOperation: Operation { super.init() name = "PurgeLocalDatabaseOperation" - qualityOfService = .userInteractive + qualityOfService = .userInitiated } override func main() { diff --git a/Source/Classes/Push/PushOperationQueue.swift b/Source/Classes/Push/PushOperationQueue.swift index 14594a0..b8a3083 100644 --- a/Source/Classes/Push/PushOperationQueue.swift +++ b/Source/Classes/Push/PushOperationQueue.swift @@ -49,7 +49,7 @@ class PushOperationQueue: OperationQueue { let modifyRecords = CKModifyRecordsOperation(recordsToSave: recordsToSave, recordIDsToDelete: recordIDsToDelete) modifyRecords.database = database modifyRecords.savePolicy = .changedKeys - modifyRecords.qualityOfService = .userInteractive + modifyRecords.qualityOfService = .userInitiated modifyRecords.perRecordCompletionBlock = { record, error in if let error = error { diff --git a/Source/Classes/Setup/CreateCloudCoreZoneOperation.swift b/Source/Classes/Setup/CreateCloudCoreZoneOperation.swift index 374caf7..00285a8 100644 --- a/Source/Classes/Setup/CreateCloudCoreZoneOperation.swift +++ b/Source/Classes/Setup/CreateCloudCoreZoneOperation.swift @@ -18,7 +18,7 @@ class CreateCloudCoreZoneOperation: AsynchronousOperation { super.init() name = "CreateCloudCoreZoneOperation" - qualityOfService = .userInteractive + qualityOfService = .userInitiated } override func main() { @@ -26,6 +26,7 @@ class CreateCloudCoreZoneOperation: AsynchronousOperation { let cloudCoreZone = CKRecordZone(zoneName: CloudCore.config.zoneName) let recordZoneOperation = CKModifyRecordZonesOperation(recordZonesToSave: [cloudCoreZone], recordZoneIDsToDelete: nil) + recordZoneOperation.qualityOfService = .userInitiated recordZoneOperation.modifyRecordZonesCompletionBlock = { if let error = $2 { self.errorBlock?(error) diff --git a/Source/Classes/Setup/PushAllLocalDataOperation.swift b/Source/Classes/Setup/PushAllLocalDataOperation.swift index 2ca681a..3660062 100644 --- a/Source/Classes/Setup/PushAllLocalDataOperation.swift +++ b/Source/Classes/Setup/PushAllLocalDataOperation.swift @@ -31,7 +31,7 @@ class PushAllLocalDataOperation: Operation { super.init() name = "PushAllLocalDataOperation" - qualityOfService = .userInteractive + qualityOfService = .userInitiated } override func main() { diff --git a/Source/Classes/Setup/SetupOperation.swift b/Source/Classes/Setup/SetupOperation.swift index f65f2e6..03e7b47 100644 --- a/Source/Classes/Setup/SetupOperation.swift +++ b/Source/Classes/Setup/SetupOperation.swift @@ -32,7 +32,7 @@ class SetupOperation: Operation { super.init() name = "SetupOperation" - qualityOfService = .userInteractive + qualityOfService = .userInitiated } private let queue = OperationQueue() diff --git a/Source/Classes/Setup/SubscribeOperation.swift b/Source/Classes/Setup/SubscribeOperation.swift index 1b2dded..ef625fb 100644 --- a/Source/Classes/Setup/SubscribeOperation.swift +++ b/Source/Classes/Setup/SubscribeOperation.swift @@ -19,7 +19,7 @@ class SubscribeOperation: AsynchronousOperation { super.init() name = "SubscribeOperation" - qualityOfService = .userInteractive + qualityOfService = .userInitiated } override func main() { @@ -75,7 +75,7 @@ class SubscribeOperation: AsynchronousOperation { } } - modifySubscriptions.qualityOfService = .userInteractive + modifySubscriptions.qualityOfService = .userInitiated return modifySubscriptions } @@ -89,7 +89,7 @@ class SubscribeOperation: AsynchronousOperation { operationToCancel.cancel() } } - fetchSubscriptions.qualityOfService = .userInteractive + fetchSubscriptions.qualityOfService = .userInitiated return fetchSubscriptions } From fde7deea14b0707fe2767ca6a42ed628013a2aef Mon Sep 17 00:00:00 2001 From: deeje Date: Wed, 26 Jan 2022 14:01:37 -0800 Subject: [PATCH 2/6] more qualityOfService = .userInitiated --- .../Pull/PublicSubscriptions/PublicDatabaseSubscriptions.swift | 2 ++ Source/Classes/Sharing/CloudCoreSharingController.swift | 1 + 2 files changed, 3 insertions(+) diff --git a/Source/Classes/Pull/PublicSubscriptions/PublicDatabaseSubscriptions.swift b/Source/Classes/Pull/PublicSubscriptions/PublicDatabaseSubscriptions.swift index 6e399c6..f69bdb3 100644 --- a/Source/Classes/Pull/PublicSubscriptions/PublicDatabaseSubscriptions.swift +++ b/Source/Classes/Pull/PublicSubscriptions/PublicDatabaseSubscriptions.swift @@ -44,6 +44,7 @@ public class PublicDatabaseSubscriptions { let config = CKOperation.Configuration() config.timeoutIntervalForResource = 20 + config.qualityOfService = .userInitiated modifySubscriptions.configuration = config CloudCore.config.container.publicCloudDatabase.add(modifySubscriptions) @@ -67,6 +68,7 @@ public class PublicDatabaseSubscriptions { let config = CKOperation.Configuration() config.timeoutIntervalForResource = 20 + config.qualityOfService = .userInitiated modifySubscription.configuration = config CloudCore.config.container.publicCloudDatabase.add(modifySubscription) diff --git a/Source/Classes/Sharing/CloudCoreSharingController.swift b/Source/Classes/Sharing/CloudCoreSharingController.swift index caa3f81..39349f0 100644 --- a/Source/Classes/Sharing/CloudCoreSharingController.swift +++ b/Source/Classes/Sharing/CloudCoreSharingController.swift @@ -49,6 +49,7 @@ public class CloudCoreSharingController: NSObject, UICloudSharingControllerDeleg let sharingController = UICloudSharingController { _, handler in let modifyOp = CKModifyRecordsOperation(recordsToSave: [aRecord, share], recordIDsToDelete: nil) modifyOp.savePolicy = .changedKeys + modifyOp.qualityOfService = .userInitiated modifyOp.modifyRecordsCompletionBlock = { records, recordIDs, error in if let share = records?.first as? CKShare { handler(share, CloudCore.config.container, error) From f50d8d77c27e637a983012510a390762d5ab7faa Mon Sep 17 00:00:00 2001 From: deeje Date: Wed, 26 Jan 2022 14:11:11 -0800 Subject: [PATCH 3/6] CloudCore.perform { configuredcontainer in } --- Source/Classes/CloudCore.swift | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Source/Classes/CloudCore.swift b/Source/Classes/CloudCore.swift index 02e9e2f..12e5351 100644 --- a/Source/Classes/CloudCore.swift +++ b/Source/Classes/CloudCore.swift @@ -256,5 +256,21 @@ open class CloudCore { delegate?.error(error: subscriptionError, module: nil) } - + + static public func perform(completion: ((CKContainer) -> Void)) { + let container = config.container + + if #available(iOSApplicationExtension 15.0, *) { + let ckConfig = CKOperation.Configuration() +// ckConfig.container = container + ckConfig.qualityOfService = .userInitiated + ckConfig.allowsCellularAccess = true + container.configuredWith(configuration: ckConfig, group: nil) { configuredContainer in + completion(configuredContainer) + } + } else { + completion(container) + } + } + } From 1336c13fbdfab74a1c73fb445d42b6137cca2056 Mon Sep 17 00:00:00 2001 From: deeje Date: Sat, 19 Mar 2022 12:03:54 -0700 Subject: [PATCH 4/6] fix use of #availability --- Source/Classes/CloudCore.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Classes/CloudCore.swift b/Source/Classes/CloudCore.swift index 12e5351..f17ef18 100644 --- a/Source/Classes/CloudCore.swift +++ b/Source/Classes/CloudCore.swift @@ -260,7 +260,7 @@ open class CloudCore { static public func perform(completion: ((CKContainer) -> Void)) { let container = config.container - if #available(iOSApplicationExtension 15.0, *) { + if #available(iOS 15.0, *) { let ckConfig = CKOperation.Configuration() // ckConfig.container = container ckConfig.qualityOfService = .userInitiated From 271b9537757b9f674f05d4e9e93ebad52b62affe Mon Sep 17 00:00:00 2001 From: deeje Date: Sat, 19 Mar 2022 12:04:25 -0700 Subject: [PATCH 5/6] explicitly import CloudKit in Example AppDelegate --- Example/Sources/AppDelegate.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Example/Sources/AppDelegate.swift b/Example/Sources/AppDelegate.swift index c782930..26460f9 100644 --- a/Example/Sources/AppDelegate.swift +++ b/Example/Sources/AppDelegate.swift @@ -8,6 +8,7 @@ import UIKit import CoreData +import CloudKit import CloudCore import Connectivity From ba0187933f229a58fdcc7d116b8e26fab02aa5a8 Mon Sep 17 00:00:00 2001 From: deeje Date: Sat, 19 Mar 2022 12:06:47 -0700 Subject: [PATCH 6/6] bump podspec s.version = 4.0.2 --- CloudCore.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CloudCore.podspec b/CloudCore.podspec index 7aab3e4..a59a72c 100755 --- a/CloudCore.podspec +++ b/CloudCore.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "CloudCore" s.summary = "Framework that enables synchronization between CloudKit and Core Data." - s.version = "4.0.1" + s.version = "4.0.2" s.homepage = "https://github.com/deeje/CloudCore" s.license = 'MIT' s.author = { "deeje" => "deeje@mac.com", "Vasily Ulianov" => "vasily@me.com" }