diff --git a/CloudKitGDPR.xcodeproj/project.pbxproj b/CloudKitGDPR.xcodeproj/project.pbxproj index ea5b02c..a5018bc 100644 --- a/CloudKitGDPR.xcodeproj/project.pbxproj +++ b/CloudKitGDPR.xcodeproj/project.pbxproj @@ -281,7 +281,7 @@ }; FE0EDBE820991B5800CC16BF /* ZIPFoundationTests.xctest */ = { isa = PBXReferenceProxy; - fileType = file; + fileType = wrapper.cfbundle; path = ZIPFoundationTests.xctest; remoteRef = FE0EDBE720991B5800CC16BF /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; @@ -369,7 +369,7 @@ CODE_SIGN_ENTITLEMENTS = "CloudKitGDPR iOS Demo/Demo.entitlements"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = "CloudKitGDPR iOS Demo/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -389,7 +389,7 @@ CODE_SIGN_ENTITLEMENTS = "CloudKitGDPR iOS Demo/Demo.entitlements"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = "CloudKitGDPR iOS Demo/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -546,16 +546,20 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 12.0; PRODUCT_BUNDLE_IDENTIFIER = me.arturgrigor.CloudKitGDPR; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TVOS_DEPLOYMENT_TARGET = 15.0; + WATCHOS_DEPLOYMENT_TARGET = 8.0; }; name = Debug; }; @@ -569,15 +573,19 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 12.0; PRODUCT_BUNDLE_IDENTIFIER = me.arturgrigor.CloudKitGDPR; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + TVOS_DEPLOYMENT_TARGET = 15.0; + WATCHOS_DEPLOYMENT_TARGET = 8.0; }; name = Release; }; diff --git a/README.md b/README.md index 222b335..11e2a84 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ Swift framework for allowing users to manage data stored in iCloud. This project ## Requirements -- iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 3.0+ -- Xcode 10.2+ -- Swift 5.0+ +- iOS 15.0+ / macOS 12+ / tvOS 15.0+ / watchOS 8.0+ +- Xcode 13.0+ +- Swift 5.5+ ## Installation diff --git a/Sources/CKDatabase+AllRecords.swift b/Sources/CKDatabase+AllRecords.swift index a7f869f..a8ddee7 100644 --- a/Sources/CKDatabase+AllRecords.swift +++ b/Sources/CKDatabase+AllRecords.swift @@ -27,10 +27,15 @@ public extension CKDatabase { let operation = CKQueryOperation(query: query) operation.resultsLimit = CKQueryOperation.maximumResults operation.zoneID = zoneID - operation.recordFetchedBlock = { record in - result.append(record) + operation.recordMatchedBlock = { recordID, fetchedResult in + switch fetchedResult { + case .success(let record): + result.append(record) + case .failure(let error): + completion(nil, error) + } } - operation.queryCompletionBlock = self.queryCompletionBlock(forInitialOperation: operation) { error in + operation.queryResultBlock = self.queryCompletionBlock(forInitialOperation: operation) { error in if let error = error { completion(nil, error) } else { @@ -47,23 +52,24 @@ public extension CKDatabase { /// - Parameters: /// - initialOperation: The initial operation. /// - completion: A closure that will be called after fetching all data. - fileprivate func queryCompletionBlock(forInitialOperation initialOperation: CKQueryOperation, completion: @escaping (Error?) -> Void) -> ((CKQueryOperation.Cursor?, Error?) -> Void) { - return { cursor, error in - if let error = error { + fileprivate func queryCompletionBlock(forInitialOperation initialOperation: CKQueryOperation, completion: @escaping (Error?) -> Void) -> ((Result) -> Void) { + return { result in + switch result { + case .success(let cursor): + if let cursor = cursor { + let newOperation = CKQueryOperation(cursor: cursor) + newOperation.resultsLimit = initialOperation.resultsLimit + newOperation.zoneID = initialOperation.zoneID + newOperation.recordMatchedBlock = initialOperation.recordMatchedBlock + newOperation.queryResultBlock = self.queryCompletionBlock(forInitialOperation: newOperation, completion: completion) + self.add(newOperation) + } else { + completion(nil) + } + case .failure(let error): completion(error) return } - - if let cursor = cursor { - let newOperation = CKQueryOperation(cursor: cursor) - newOperation.resultsLimit = initialOperation.resultsLimit - newOperation.zoneID = initialOperation.zoneID - newOperation.recordFetchedBlock = initialOperation.recordFetchedBlock - newOperation.queryCompletionBlock = self.queryCompletionBlock(forInitialOperation: newOperation, completion: completion) - self.add(newOperation) - } else { - completion(nil) - } } } diff --git a/Sources/GDPR.swift b/Sources/GDPR.swift index 5a54c48..928d96b 100644 --- a/Sources/GDPR.swift +++ b/Sources/GDPR.swift @@ -154,6 +154,7 @@ open class GDPR { let dispatchGroup = DispatchGroup() let containers = self.metadata.keys var result: RecordsZoneIDsByContainer = [:] + var zonesDeleted: [CKRecordZone.ID] = [] for container in containers { guard failure == nil else { @@ -182,18 +183,28 @@ open class GDPR { let deletionOperation = CKModifyRecordZonesOperation(recordZonesToSave: nil, recordZoneIDsToDelete: zoneIDs) dispatchGroup.enter() - deletionOperation.modifyRecordZonesCompletionBlock = { _, deletedZones, error in + + deletionOperation.perRecordZoneDeleteBlock = { zoneId, result in + switch result { + case .success(_): + zonesDeleted.append(zoneId) + case .failure(let error): + failure = error + } + } + + deletionOperation.modifyRecordZonesResultBlock = { zoneResult in defer { dispatchGroup.leave() } - - if let error = error { + switch zoneResult { + case .success(_): + let deletedZones = zonesDeleted + result[container] = deletedZones + case .failure(let error): failure = error return } - - let deletedZones = deletedZones ?? [] - result[container] = deletedZones } database.add(deletionOperation)