From c5e1942d8fb5fd8b4c599609283fc7ed26d32895 Mon Sep 17 00:00:00 2001 From: Idriss Mrabti Date: Sun, 12 Jun 2022 10:01:33 +0200 Subject: [PATCH 1/2] Initial configuration of NSPersistentCloudKitContainer --- CocktailBucket (iOS).entitlements | 23 +++++++++++++++++++ CocktailBucket (macOS).entitlements | 23 +++++++++++++++++++ CocktailBucket--iOS--Info.plist | 12 ++++++++++ CocktailBucket.xcodeproj/project.pbxproj | 28 ++++++++++++++++++++++++ Shared/Persistence.swift | 24 ++++++++++++++++++-- 5 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 CocktailBucket (iOS).entitlements create mode 100644 CocktailBucket (macOS).entitlements create mode 100644 CocktailBucket--iOS--Info.plist diff --git a/CocktailBucket (iOS).entitlements b/CocktailBucket (iOS).entitlements new file mode 100644 index 0000000..a3f099f --- /dev/null +++ b/CocktailBucket (iOS).entitlements @@ -0,0 +1,23 @@ + + + + + aps-environment + development + com.apple.developer.icloud-container-identifiers + + iCloud.com.example.apple-samplecode.CoreDataCloudKitDemo5VTM8F229V + + com.apple.developer.icloud-services + + CloudDocuments + CloudKit + + com.apple.developer.ubiquity-container-identifiers + + iCloud.com.example.apple-samplecode.CoreDataCloudKitDemo5VTM8F229V + + com.apple.developer.ubiquity-kvstore-identifier + $(TeamIdentifierPrefix)$(CFBundleIdentifier) + + diff --git a/CocktailBucket (macOS).entitlements b/CocktailBucket (macOS).entitlements new file mode 100644 index 0000000..628366c --- /dev/null +++ b/CocktailBucket (macOS).entitlements @@ -0,0 +1,23 @@ + + + + + com.apple.developer.aps-environment + development + com.apple.developer.icloud-container-identifiers + + iCloud.com.example.apple-samplecode.CoreDataCloudKitDemo5VTM8F229V + + com.apple.developer.icloud-services + + CloudDocuments + CloudKit + + com.apple.developer.ubiquity-container-identifiers + + iCloud.com.example.apple-samplecode.CoreDataCloudKitDemo5VTM8F229V + + com.apple.developer.ubiquity-kvstore-identifier + $(TeamIdentifierPrefix)$(CFBundleIdentifier) + + diff --git a/CocktailBucket--iOS--Info.plist b/CocktailBucket--iOS--Info.plist new file mode 100644 index 0000000..634f4e4 --- /dev/null +++ b/CocktailBucket--iOS--Info.plist @@ -0,0 +1,12 @@ + + + + + UIBackgroundModes + + fetch + processing + remote-notification + + + diff --git a/CocktailBucket.xcodeproj/project.pbxproj b/CocktailBucket.xcodeproj/project.pbxproj index 05b589b..e46ce66 100644 --- a/CocktailBucket.xcodeproj/project.pbxproj +++ b/CocktailBucket.xcodeproj/project.pbxproj @@ -23,6 +23,8 @@ F9CD5D402679E5FA008AED32 /* BucketListDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9CD5D3E2679E5FA008AED32 /* BucketListDetail.swift */; }; F9CD5D422679E61C008AED32 /* EditCocktail.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9CD5D412679E61C008AED32 /* EditCocktail.swift */; }; F9CD5D432679E61C008AED32 /* EditCocktail.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9CD5D412679E61C008AED32 /* EditCocktail.swift */; }; + F9DCF6932850A4000068AE34 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9DCF6922850A4000068AE34 /* CloudKit.framework */; }; + F9DCF6962850A40F0068AE34 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9DCF6952850A40F0068AE34 /* CloudKit.framework */; }; F9F9D4122844B26800DC4B06 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9F9D4112844B26800DC4B06 /* Persistence.swift */; }; F9F9D4132844B26800DC4B06 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9F9D4112844B26800DC4B06 /* Persistence.swift */; }; F9F9D41528466ACC00DC4B06 /* BucketList+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9F9D41428466ACC00DC4B06 /* BucketList+Extensions.swift */; }; @@ -51,6 +53,11 @@ F9CD5D3B2679E5CE008AED32 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = ""; }; F9CD5D3E2679E5FA008AED32 /* BucketListDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BucketListDetail.swift; sourceTree = ""; }; F9CD5D412679E61C008AED32 /* EditCocktail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCocktail.swift; sourceTree = ""; }; + F9DCF68F2850A3EE0068AE34 /* CocktailBucket--iOS--Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "CocktailBucket--iOS--Info.plist"; sourceTree = ""; }; + F9DCF6902850A3FC0068AE34 /* CocktailBucket (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "CocktailBucket (iOS).entitlements"; sourceTree = ""; }; + F9DCF6922850A4000068AE34 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.5.sdk/System/Library/Frameworks/CloudKit.framework; sourceTree = DEVELOPER_DIR; }; + F9DCF6942850A40B0068AE34 /* CocktailBucket (macOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "CocktailBucket (macOS).entitlements"; sourceTree = ""; }; + F9DCF6952850A40F0068AE34 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; }; F9F9D4112844B26800DC4B06 /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; F9F9D41428466ACC00DC4B06 /* BucketList+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BucketList+Extensions.swift"; sourceTree = ""; }; F9F9D41728466DB900DC4B06 /* Cocktail+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Cocktail+Extensions.swift"; sourceTree = ""; }; @@ -66,6 +73,7 @@ buildActionMask = 2147483647; files = ( F9F9D428284E06A300DC4B06 /* CropViewController in Frameworks */, + F9DCF6932850A4000068AE34 /* CloudKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -73,6 +81,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F9DCF6962850A40F0068AE34 /* CloudKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -82,8 +91,12 @@ F9CD5D012679CBEF008AED32 = { isa = PBXGroup; children = ( + F9DCF6942850A40B0068AE34 /* CocktailBucket (macOS).entitlements */, + F9DCF6902850A3FC0068AE34 /* CocktailBucket (iOS).entitlements */, + F9DCF68F2850A3EE0068AE34 /* CocktailBucket--iOS--Info.plist */, F9CD5D062679CBEF008AED32 /* Shared */, F9CD5D122679CBF0008AED32 /* Products */, + F9DCF6912850A4000068AE34 /* Frameworks */, ); sourceTree = ""; }; @@ -134,6 +147,15 @@ path = Views; sourceTree = ""; }; + F9DCF6912850A4000068AE34 /* Frameworks */ = { + isa = PBXGroup; + children = ( + F9DCF6952850A40F0068AE34 /* CloudKit.framework */, + F9DCF6922850A4000068AE34 /* CloudKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -399,11 +421,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "CocktailBucket (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 5VTM8F229V; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "CocktailBucket--iOS--Info.plist"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -429,11 +453,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "CocktailBucket (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 5VTM8F229V; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "CocktailBucket--iOS--Info.plist"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -460,6 +486,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "CocktailBucket (macOS).entitlements"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; @@ -489,6 +516,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "CocktailBucket (macOS).entitlements"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; diff --git a/Shared/Persistence.swift b/Shared/Persistence.swift index edb91b2..5bb9ea4 100644 --- a/Shared/Persistence.swift +++ b/Shared/Persistence.swift @@ -8,6 +8,10 @@ import Foundation import CoreData +// MARK: - Creating Contexts + +let appTransactionAuthorName = "app" + class PersistenceController: ObservableObject { static let shared = PersistenceController() @@ -26,16 +30,32 @@ class PersistenceController: ObservableObject { return url }() - let container: NSPersistentContainer + let container: NSPersistentCloudKitContainer init() { - container = NSPersistentContainer(name: "CocktailBucket") + container = NSPersistentCloudKitContainer(name: "CocktailBucket") + + let privateStoreDescription = container.persistentStoreDescriptions.first! + let storesURL = privateStoreDescription.url!.deletingLastPathComponent() + privateStoreDescription.url = storesURL.appendingPathComponent("private.sqlite") + privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) + privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) + + container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy + container.viewContext.transactionAuthor = appTransactionAuthorName + + // Pin the viewContext to the current generation token and set it to keep itself up to date with local changes. container.viewContext.automaticallyMergesChangesFromParent = true + do { + try container.viewContext.setQueryGenerationFrom(.current) + } catch { + fatalError("###\(#function): Failed to pin viewContext to the current generation:\(error)") + } } } From 99daec143838f7a38abb618f89b138b5d503ddfe Mon Sep 17 00:00:00 2001 From: Idriss Mrabti Date: Thu, 23 Jun 2022 10:15:37 +0200 Subject: [PATCH 2/2] viewContext reset causing an issue --- Shared/Views/EditCocktail.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Shared/Views/EditCocktail.swift b/Shared/Views/EditCocktail.swift index d90bde1..5bc432c 100644 --- a/Shared/Views/EditCocktail.swift +++ b/Shared/Views/EditCocktail.swift @@ -243,7 +243,6 @@ struct EditCocktail: View { createOrUpdateCocktailPicture() try? viewContext.save() - viewContext.reset() } private func createOrUpdateCocktailPicture() {