← All repositories

listless

A simple list app for Apple platforms

git clone https://code.inqk.net/listless.git


Listless/Sync/CloudKitErrorClassifier.swift (1948B)

1import CloudKit
2import Foundation
3
4enum SyncIssue {
5    case transient(message: String)
6    case deferred(message: String)
7}
8
9enum 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}