CloudKitErrorClassifier.swift (1948B)
1 import CloudKit 2 import Foundation 3 4 enum SyncIssue { 5 case transient(message: String) 6 case deferred(message: String) 7 } 8 9 enum CloudKitErrorClassifier { 10 static func classify(_ error: Error) -> SyncIssue { 11 let rootError = unwrap(error) 12 let nsError = rootError as NSError 13 14 if nsError.domain == CKError.errorDomain, 15 let ckCode = CKError.Code(rawValue: nsError.code) 16 { 17 return classifyCloudKit(code: ckCode) 18 } 19 20 return .transient(message: "Saved locally. iCloud sync will retry automatically.") 21 } 22 23 private static func classifyCloudKit(code: CKError.Code) -> SyncIssue { 24 switch code { 25 case .networkUnavailable, .networkFailure, .serviceUnavailable, .requestRateLimited, 26 .zoneBusy, .serverResponseLost, .operationCancelled: 27 return .transient(message: "Saved locally. iCloud sync will retry automatically.") 28 29 case .notAuthenticated: 30 return .transient(message: "Sign in to iCloud to sync across devices.") 31 32 case .quotaExceeded: 33 return .transient(message: "iCloud storage full. Free up space to continue syncing.") 34 35 case .permissionFailure, .badContainer, .missingEntitlement: 36 return .transient(message: "iCloud sync unavailable. Check iCloud settings.") 37 38 case .accountTemporarilyUnavailable, .zoneNotFound, .userDeletedZone: 39 return .deferred(message: "Saved locally. iCloud sync will retry automatically.") 40 41 default: 42 return .deferred(message: "Saved locally. iCloud sync will retry automatically.") 43 } 44 } 45 46 private static func unwrap(_ error: Error) -> Error { 47 if let storeError = error as? ItemStoreError { 48 switch storeError { 49 case .fetchFailed(let wrappedError), .saveFailed(let wrappedError): 50 return wrappedError 51 } 52 } 53 return error 54 } 55 }