From e97d7b4c9e24908d7823b8ee5c37584cfc216476 Mon Sep 17 00:00:00 2001 From: josephktcheung Date: Thu, 15 Jul 2021 15:16:45 +0800 Subject: [PATCH 1/2] Customize CKRecord.ReferenceAction --- README.md | 6 ++++++ Shared/Example Objects/School.swift | 9 +++++++++ Source/Classes/CKRecordRepresentable.swift | 2 ++ Source/Classes/Encoder/CKEncoderKeyedContainer.swift | 10 ++++++---- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b3b8995..f5eb632 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,12 @@ func ignoredProperties() -> [String] ``` which how its name suggests, let you ignore some properties from being encoded in the resultant `CKRecord`. +You can implement the function +```swift +func cloudKitReferenceActions() -> [String: CKRecord.ReferenceAction] +``` +which how its name suggests, let you set `CKRecord.ReferenceAction` for any reference property. The default action is `.deleteSelf`. + ### CLLocation `CLLocation` properties has a special behavior. Since they are primitive types for `CloudKit` but they are not for `Codable` protocol, it was necessary to create a workaround to encode/decode them. diff --git a/Shared/Example Objects/School.swift b/Shared/Example Objects/School.swift index 3322058..9583f7d 100644 --- a/Shared/Example Objects/School.swift +++ b/Shared/Example Objects/School.swift @@ -9,6 +9,7 @@ import CoreLocation import NestedCloudKitCodable import UIKit +import CloudKit // swiftlint:disable implicitly_unwrapped_optional struct School: CKCodable { @@ -61,4 +62,12 @@ struct School: CKCodable { try container.encode(director, forKey: .director) try container.encode(books, forKey: .books) } + + func cloudKitReferenceActions() -> [String : CKRecord.ReferenceAction] { + return [ + "students": .deleteSelf, + "director": .deleteSelf, + "books": .none + ] + } } diff --git a/Source/Classes/CKRecordRepresentable.swift b/Source/Classes/CKRecordRepresentable.swift index 80e4df7..6e9beb6 100644 --- a/Source/Classes/CKRecordRepresentable.swift +++ b/Source/Classes/CKRecordRepresentable.swift @@ -14,10 +14,12 @@ public protocol CKRecordRepresentable { var cloudKitIdentifier: String { get } func ignoredProperties() -> [String] + func cloudKitReferenceActions() -> [String: CKRecord.ReferenceAction] } public extension CKRecordRepresentable { func ignoredProperties() -> [String] { return [] } + func cloudKitReferenceActions() -> [String: CKRecord.ReferenceAction] { return [:] } } public typealias CKEncodable = CKRecordRepresentable & Encodable diff --git a/Source/Classes/Encoder/CKEncoderKeyedContainer.swift b/Source/Classes/Encoder/CKEncoderKeyedContainer.swift index c0624e2..7c07d93 100644 --- a/Source/Classes/Encoder/CKEncoderKeyedContainer.swift +++ b/Source/Classes/Encoder/CKEncoderKeyedContainer.swift @@ -71,7 +71,7 @@ extension CKEncoderKeyedContainer: KeyedEncodingContainerProtocol { // MARK: Auxiliar Encode functions private func encodeSingleValue(_ value: CKEncodable, forKey key: Key) throws { - storage[key.stringValue] = try produceReference(for: value) + storage[key.stringValue] = try produceReference(for: value, key: key) let encoder = CloudKitRecordEncoder(object: value, zoneID: zoneID, createdRecords: createdRecords) @@ -87,7 +87,7 @@ extension CKEncoderKeyedContainer: KeyedEncodingContainerProtocol { forKey key: Key) throws where T: Encodable { var references = [CKRecord.Reference]() try castedValues.forEach { - let reference = try produceReference(for: $0) + let reference = try produceReference(for: $0, key: key) references.append(reference) } storage[key.stringValue] = references as CKRecordValue @@ -198,9 +198,11 @@ extension CKEncoderKeyedContainer: KeyedEncodingContainerProtocol { storage[key.stringValue] = locations as CKRecordValue } - private func produceReference(for value: CKEncodable) throws -> CKRecord.Reference { + private func produceReference(for value: CKEncodable, key: Key) throws -> CKRecord.Reference { let recordID = CKRecord.ID(recordName: value.cloudKitIdentifier, zoneID: zoneID ?? .default) - return CKRecord.Reference(recordID: recordID, action: .deleteSelf) + let actions = object.cloudKitReferenceActions() + let action = actions[key.stringValue] ?? .deleteSelf + return CKRecord.Reference(recordID: recordID, action: action) } func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { From 00dbd0b0caac49ab9e101023f59b39f3ba9c1b9a Mon Sep 17 00:00:00 2001 From: josephktcheung Date: Mon, 19 Jul 2021 14:00:53 +0800 Subject: [PATCH 2/2] Use CKRecord.Reference.Action as CKRecord.ReferenceAction is only available in Xcode 13 --- README.md | 4 ++-- Shared/Example Objects/School.swift | 2 +- Source/Classes/CKRecordRepresentable.swift | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f5eb632..14f16b2 100644 --- a/README.md +++ b/README.md @@ -58,9 +58,9 @@ which how its name suggests, let you ignore some properties from being encoded i You can implement the function ```swift -func cloudKitReferenceActions() -> [String: CKRecord.ReferenceAction] +func cloudKitReferenceActions() -> [String: CKRecord.Reference.Action] ``` -which how its name suggests, let you set `CKRecord.ReferenceAction` for any reference property. The default action is `.deleteSelf`. +which how its name suggests, let you set `CKRecord.Reference.Action` for any reference property. The default action is `.deleteSelf`. ### CLLocation diff --git a/Shared/Example Objects/School.swift b/Shared/Example Objects/School.swift index 9583f7d..46db624 100644 --- a/Shared/Example Objects/School.swift +++ b/Shared/Example Objects/School.swift @@ -63,7 +63,7 @@ struct School: CKCodable { try container.encode(books, forKey: .books) } - func cloudKitReferenceActions() -> [String : CKRecord.ReferenceAction] { + func cloudKitReferenceActions() -> [String : CKRecord.Reference.Action] { return [ "students": .deleteSelf, "director": .deleteSelf, diff --git a/Source/Classes/CKRecordRepresentable.swift b/Source/Classes/CKRecordRepresentable.swift index 6e9beb6..5886c3b 100644 --- a/Source/Classes/CKRecordRepresentable.swift +++ b/Source/Classes/CKRecordRepresentable.swift @@ -14,12 +14,12 @@ public protocol CKRecordRepresentable { var cloudKitIdentifier: String { get } func ignoredProperties() -> [String] - func cloudKitReferenceActions() -> [String: CKRecord.ReferenceAction] + func cloudKitReferenceActions() -> [String: CKRecord.Reference.Action] } public extension CKRecordRepresentable { func ignoredProperties() -> [String] { return [] } - func cloudKitReferenceActions() -> [String: CKRecord.ReferenceAction] { return [:] } + func cloudKitReferenceActions() -> [String: CKRecord.Reference.Action] { return [:] } } public typealias CKEncodable = CKRecordRepresentable & Encodable