I'm having some trouble with the following function from the CKSyncEngineDelegate protocol.
func nextRecordZoneChangeBatch(_ context: CKSyncEngine.SendChangesContext,
syncEngine: CKSyncEngine) async -> CKSyncEngine.RecordZoneChangeBatch? {
The sample code from the documentation is
func nextRecordZoneChangeBatch(
_ context: CKSyncEngine.SendChangesContext,
syncEngine: CKSyncEngine
) async -> CKSyncEngine.RecordZoneChangeBatch? {
// Get the pending record changes and filter by the context's scope.
let pendingChanges = syncEngine.state.pendingRecordZoneChanges
.filter { context.options.zoneIDs.contains($0) }
// Return a change batch that contains the corresponding materialized records.
return await CKSyncEngine.RecordZoneChangeBatch(
pendingChanges: pendingChanges) { self.recordFor(id: $0) }
}
init?(pendingChanges: [CKSyncEngine.PendingRecordZoneChange], recordProvider: (CKRecord.ID) -> (CKRecord?)) works fine for the sample app which only has one record type, but it seems incredible inefficient for my app which has a dozen different record types. The recordProvider gives you a CKRecord.ID, but not the CKRecord.RecordType. Searching each record type for a matching ID seems very inefficient.
Doesn't the CKSyncEngine.PendingRecordZoneChange contain an array of CKRecords, not just CKRecord.IDs? According to the documentation CKSyncEngine.RecordZoneChangeBatch has a recordsToSave property, but Xcode reports 'CKSyncEngine.PendingRecordZoneChange' has no member 'recordsToSave'
I'm looking for someway to get the CKRecords from syncEngine.state.pendingRecordZoneChanges.
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Post
Replies
Boosts
Views
Activity
I implemented to my app iCloud backup and restore services. Basically App uploads it's document directory files to iCloud using NSURL containerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; and [fileManager copyItemAtURL:fileURL toURL:destinationURL error:&error]; and everything has been OK to upload files. By checking my iCloud account, it has taken the space needed to store those files.
However, when I changed my decice, I'm unable to get those files back. At first, files had .icloud extra extension added, but now the function just reports only 5 files from few hunder. The function used to get backup files is:
`- (NSArray) getBackupFiles {
NSError *error;
NSURL *containerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (!containerURL) return nil;
// NSArray *keysArray = [[NSArray alloc] initWithObjects: nil];
NSArray *resultsArray = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:containerURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles error:&error];
if (error) {
[self myAlertView:error.localizedDescription];
return nil;
}
else return resultsArray;
}
Any ideas, what went wrong?`
Hey everyone,
I'm trying to get the user's name to display in a welcome screen, but unfortunatelly no success so far.
For that, I'm using CKContainer.default().shareParticipant(forUserRecordID: recordID).userIdentity.nameComponents, but the returned nameComponents are empty, despite receiving no error and accountStatus of .available.
Here's my code:
struct Helper {
static func getUserInformation() async throws -> Models.UserInfo {
let container = CKContainer.default()
let accountStatus = try! await container.accountStatus()
var accountStatusDescription = ""
switch accountStatus {
case .couldNotDetermine:
accountStatusDescription = "couldNotDetermine"
case .available:
accountStatusDescription = "available"
case .restricted:
accountStatusDescription = "restricted"
case .noAccount:
accountStatusDescription = "noAccount"
case .temporarilyUnavailable:
accountStatusDescription = "temporarilyUnavailable"
@unknown default:
accountStatusDescription = "default"
}
print("[Helper] CKContainer accountStatus: \(accountStatusDescription) ")
// Prints "[Helper] CKContainer accountStatus: available"
do {
let recordID = try await container.userRecordID()
let id = recordID.recordName
let participant = try await container.shareParticipant(forUserRecordID: recordID)
guard let nameComponents = participant.userIdentity.nameComponents else {
throw Models.ServiceError.userIdentityUnknownName
}
print("[Helper] CKShare.Participant nameComponents \(nameComponents)")
// Prints "[Helper] CKShare.Participant nameComponents - "
print("[Helper] CKShare nameComponents.givenName \(String(describing: nameComponents.givenName))")
print("[Helper] CKShare nameComponents.nickname \(String(describing: nameComponents.nickname))")
print("[Helper] CKShare nameComponents.familyName \(String(describing: nameComponents.familyName))")
print("[Helper] CKShare nameComponents.namePrefix \(String(describing: nameComponents.namePrefix))")
print("[Helper] CKShare nameComponents.nameSuffix \(String(describing: nameComponents.nameSuffix))")
print("[Helper] CKShare nameComponents.middleName \(String(describing: nameComponents.middleName))")
let name = PersonNameComponentsFormatter().string(from: nameComponents)
return Models.UserInfo(
id: id,
name: name
)
} catch {
throw error
}
}
}
Other than that, this project is using CloudKit for persistence through SwiftData and everything seems to be duly setup and working fine.
Any idea of what I might be missing? Any user permissions required? As far as I understood, from iOS 17 on and using this code, no permissions are required anymore but I may be wrong.
Any hint / help would be much appreciated!
Cheers,
Jorge
I have couple of questions regarding app and schema version management related to SwiftData migration.
For instance, it's common for the schema to change from V1 to V2 when updating an app from V1 to V2 and V3.
This process seems reasonable to me.
here's Moreover, if the versions go up to V10, does this mean I need to separate and organize stages for all migration codes, such as from V1 to V2, V2 to V3, up to V10, MigrationStages and Models for such exception handling?
It was too wordy, here are my summary questions.
1. Can I limit to specific versions in my workspace?(e.g V1->2->3->1->2 .. so on)
2. if its not possible, For extensive versioning up to V10, should migration codes be organized for every incremental update for handling exceptions?
3. If I need to permanently record every stages and model, what improvements could be made to this structure?, can I get some useful tips?
What interfaces do I use to propagate a CloudKit change in a shared zone to a notification/badge to all participants in the shared zone?
Assume I have a 'League' that is the root object in a shared zone and that N Players are members of the league. One of the players, the 'organizer', schedules a 'Game' that is open to any of the players. When the organizer creates the game (in the league's shared zone) and it is mirrored in CloudKit, how can the other players see it (as a timely notification)?
I already observe .NSPersistentStoreRemoteChange on NSPersistentStoreCoordinator and NSPersistentCloudKitContainer.eventChangedNotification on NSPersistentCloudKitContainer. Are these delivered in the background? Can/Should they generate a 'local/remote' notification for handling at the AppDelegate level? How?
Do I need to use a CKDatabaseSubscription looking for CD_Game records directly? (I'd rather not; because then I'd have a potential race between the remote iCloud database(s) and the local CoreData)
Hi, I have issue when I use swift data in development and I'm beginner. I have two basic classes.
@Model
class User{
@Attribute(.unique) var id: UUID;
var account: String;
var password: String;
var name: String;
var role: Role
@Relationship(inverse: \Transaction.tranInitiator)
var transcations = [Transaction]()
init(account: String, password: String, name: String, role: Role) {
self.id = UUID()
self.account = account
self.password = password
self.name = name
self.role = role
}
}
//
@Model
class Transaction{
@Attribute(.unique) var tranId: UUID;
var tranName: String;
var tranCash: Float;
var tranDate: Date;
@Relationship var tranInitiator: User;
// init block
}
}
and when I am going to fetch items I use predictor like
let predictor = #Predicate<Transaction>{ tran in
tran.tranInitiator == user
}
fetchDescriptorTrans = FetchDescriptor(predicate: predictor)
let transList = try? contextTransaction?.fetch(fetchDescriptorTrans)
if(transList!.isEmpty){return []}
else{
return transList!
}
compiler shows error
Cannot convert value of type 'PredicateExpressions.Equal<PredicateExpressions.KeyPath<PredicateExpressions.Variable, User>, PredicateExpressions.Value>' to closure result type 'any StandardPredicateExpression'
I don't know why
I am using the public cloud database to store my application data, this data is accessed by all users of the application, but at some point it is necessary for a user who did not create a respective data in the database to delete it, but from what I read in the documentation this is not possible, only with a permission. How do I allow a user to change or delete any data created by another user in the public cloud database?
I’m having an issue when two of my SwiftData models have a one-to-many relationship and I have them synced via CloudKit.
To be clear, I’ve met all of the requirements to make it iCloud friendly and sync to work. I followed this https://www.hackingwithswift.com/quick-start/swiftdata/how-to-sync-swiftdata-with-icloud, and can confirm I’ve done it correctly because initially I was seeing this crash on startup when I had not:
Thread 1: Fatal error: Could not create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer)
This is to say, the problem may be iCloud related but it’s not due to a wrong model setup. Speaking of which, these are models:
@Model
class Film {
var name: String = ""
var releaseYear: Int = 0
var director: Director? = nil
init(name: String, releaseYear: Int, director: Director) {
self.name = name
self.releaseYear = releaseYear
self.director = director
}
}
@Model
class Director {
var name: String = ""
@Relationship(deleteRule: .cascade, inverse: \Film.director)
var films: [Film]? = []
init(name: String, films: [Film]) {
self.name = name
self.films = films
}
}
I’ve set the delete rule for the relationship between Film and Director to be cascading because you can’t have a film without a director (to be clear, even when set as nullify, it doesn’t make a difference)
And this is the @main App definition:
@main
struct mvpApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Film.self,
Director.self
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
}
And this is the dummy ContentView:
struct ContentView: View {
var body: some View {
EmptyView()
.onAppear {
let newDirector = Director(name: "Martin Scorcese", films: [])
let film = Film(name: "The Wolf of Wall Street", releaseYear: 2019, director: newDirector)
newDirector.films!.append(film)
}
}
}
I create a Director with no films assigned. I then create a Film, and the append it to the Director’s [Film] collection.
The last step however causes a crash consistently:
There is a workaround that involves removing this line from the Film init():
self.director = director // comment this out so it’s not set in a Film’s init()
When I do this, I can append the (Director-less) Film to the Director’s [Film] collection.
Am I misunderstanding how these relationships should work in SwiftData/CloudKit? It doesn’t make any sense to me that when two models are paired together that only one of them has a reference to the relationship, and the other has no knowledge of the link.
The above is a minimum reproducible example (and not my actual application). In my application, I basically compromised with the workaround that initially appears to be without consequence, but I have begun to notice crashes happening semi-regularly when deleting models that I suspect must be linked to setting the foundations incorrectly.
This piece of code was working properly until I Introduced the Exercise Model. I have tried everything like using migration scheme, removing the app, cleaning build folder, trying on different devices and simulator. Nothing seems to work now. I can't get the app to launch.
struct LogbookApp: App {
@State private var sharedModelContainer: ModelContainer = {
let schema = Schema([
Workout.self,
Exercise.self
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch(let error) {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
MainCoordinator()
.view()
}
.modelContainer(sharedModelContainer)
}
}
The models look like this
@Model
final class Exercise {
var name: String
var workout: Workout?
init(name: String, workout: Workout? = nil) {
self.name = name
self.workout = workout
}
}
@Model
final class Workout {
@Attribute(.unique) var id = UUID()
@Relationship(deleteRule: .cascade) var exercises: [Exercise]?
var type: WorkoutType
var date: Date
var duration: Int
var customDescription: String
init(id: UUID = UUID(),
type: WorkoutType,
date: Date,
duration: Int,
customDescription: String = "",
exercises: [Exercise]? = []) {
self.id = id
self.type = type
self.date = date
self.duration = duration
self.customDescription = customDescription
self.exercises = exercises
}
}
I'm running into a crash on launch in Simulator with my visionOS that uses SwiftData in Xcode Version 15.3 (15E5202a).
This is printing to the console: SwiftData/DataUtilities.swift:1093: Fatal error: Unable to parse keypath for non-PersistentModel Type, and then it's crashing on _swift_runtime_on_report.
This worked fine in Xcode 15.2.
I'll return to Xcode 15.2 for now and report an issue, but is there anyone that can translate what this even means so I can fix it?
Thanks
Hi, I'm trying to make some changes to my SwiftData model and I want to add a new non-optional property to one of my model classes.
My current model was not part of a VersionedSchema so I first encapsulated it into one
public enum FeynnDataModelsSchemaV1: VersionedSchema {
public static var versionIdentifier: Schema.Version = .init(1, 0, 0)
public static var models: [any PersistentModel.Type] {
[FeynnDataModelsSchemaV1.Workout.self, FeynnDataModelsSchemaV1.Activity.self, FeynnDataModelsSchemaV1.ActivityRecord.self, FeynnDataModelsSchemaV1.WorkoutSession.self]
}
}
Then I run the app and everything works as expected.
Secondly, I create the V2 and add the new property:
public enum FeynnDataModelsSchemaV2: VersionedSchema {
public static var versionIdentifier: Schema.Version = Schema.Version(2, 0, 0)
public static var models: [any PersistentModel.Type] {
[FeynnDataModelsSchemaV2.Workout.self, FeynnDataModelsSchemaV2.Activity.self, FeynnDataModelsSchemaV2.ActivityRecord.self, FeynnDataModelsSchemaV2.WorkoutSession.self]
}
}
extension FeynnDataModelsSchemaV2 {
@Model
final public class Activity: Hashable {
...
public var activityType: ActivityType = ActivityType.traditionalStrengthTraining
...
}
}
Lastly, I create the schema migration plan and add it to my modelContainer:
public enum FeynnDataModelsMigrationPlan: SchemaMigrationPlan {
public static var schemas: [VersionedSchema.Type] = [
FeynnDataModelsSchemaV1.self,
FeynnDataModelsSchemaV2.self
]
public static var stages: [MigrationStage] = [migrateV1toV2]
public static var migrateV1toV2 = MigrationStage.custom(fromVersion: FeynnDataModelsSchemaV1.self, toVersion: FeynnDataModelsSchemaV2.self, willMigrate: {moc in
let activities = try? moc.fetch(FetchDescriptor<Activity>())
print("\(activities?.count ?? 919191991)")
}, didMigrate: {moc in
let activities = try? moc.fetch(FetchDescriptor<Activity>())
print("\(activities?.count ?? 88888888)")
activities?.forEach { activity in activity.activityType = .traditionalStrengthTraining }
try? moc.save()
})
}
if let container = try? ModelContainer(
for: Workout.self, Activity.self, ActivityRecord.self, WorkoutSession.self,
migrationPlan: FeynnDataModelsMigrationPlan.self,
configurations: ModelConfiguration(cloudKitDatabase: .automatic)) {
self.container = container
} else {
self.container = try ModelContainer(
for: Workout.self, Activity.self, ActivityRecord.self, WorkoutSession.self,
migrationPlan: FeynnDataModelsMigrationPlan.self,
configurations: ModelConfiguration(cloudKitDatabase: .none))
}
After running this, the application runs as expected, but as soon as I render a view that references Activity.activityType the app crashes trying to get the value for my existing activities given that it is nil, pointing out that the migration stage was not ran?
None of the print statements in the didMigrate or willMigrate can be found within the logs either.
I have tried several approaches creating more VersionedSchemas and I run into more issues such as Cannot use stuck migration with an unknown model version.
I feel like the current way of handling schema versions of SwiftData is very confusing and opaque for the developer to know what is going on. I don't know if the underlying database is picking the un-versioned schema, the V1 or the V2.
Is there anything I'm doing wrong? What can I do apart from making the new property optional and having a computed property that unwraps it giving it a default value when nil?
Thank you!
i am developing a SwiftUI App, where i need to work with relatively large amounts of data sets. While processing these data i had some issues with my app crashing randomly. As i was debugging this situation for a while i found out that dataraces were the cause for these crashes. That is why i decided to use an actor for these things..
As the actor takes care of concurrent threads, i was not having any crashes anymore, BUT, now i have to deal with some memory leaks!
i've created a simple demo project to reproduce these leaks.
my view:
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
// @Query private var items: [Item]
var body: some View {
VStack {
Button(action: {
Task { await testImport() }
}, label: {
Text("Import")
})
}
}
}
the function:
func testImport() async {
let actorX = testActor(container: self.modelContext.container)
await actorX.cleanUp()
// create dummy data:
var dummyArray: [Int] = []
for i in 0...1300 {
dummyArray.append(i)
}
await actorX.saveAssets(with: dummyArray)
dummyArray = []
print("Checkpoint")
}
the actor:
actor testActor {
public var modelContainer: ModelContainer
public var modelExecutor: any ModelExecutor
private var context: ModelContext { modelExecutor.modelContext }
public init(container: ModelContainer) {
self.modelContainer = container
let context = ModelContext(modelContainer)
modelExecutor = DefaultSerialModelExecutor(modelContext: context)
}
func cleanUp() {
print("starting cleanup...")
do {
try context.delete(model: Item.self)
print("cleanup: table LocalAsset truncated")
} catch {
print("Failed to clear all LocalAsset data.")
}
}
func saveAssets(with array: [Int]) {
for i in 0..<array.count {
let foo = array[i]
let newItem = Item(timestamp: Date(), dummyInt: foo)
context.insert(newItem)
}
try? context.save()
}
}
And Here's a screenshot of Xcode's Instruments Leak tool:
i hope somebody has any idea how to get rid of those leaks..
Hey there,
I am having a question which hopefully someone can answer.
I am developing an App and wanted to store Images in SwiftData with the
@External Storage Attribute.
I get it to work with a single image and also with an array of images but...saving 1 Image shows a storage space of about 38 bytes but when I store an array of 3 Images the storage in the SQL Database (Blob Type) increases to over 8 Million Bytes?
Is this a bug or is this what it is?
I am having a direction for a workaround but it would be more convenient if it would work with SwiftData for an array of images same as it does for 1 image.
Thanks for any clarification.
I've defined 'public' and 'private' configurations in CoreData and configured the 'public' configuration to be handled in the CloudKit publicDB. The two configurations contain disjoint sets of NSManagedObject entity types. Some of the entities in the private configuration reference an entity in the public configuration using a UUID; thereby avoiding cross-configuration CoreData relationships. Avoiding this is a requirement of CoreData + CloudKit.
Now, since the UUID is meant to point to an object, in the awakeFromFetch() method I decided to fill in a transient property. No go. Even for a transient property there cannot be a cross-configuration relationship.
Why? Is there a way to avoid this constraint?
The cost of not having a transient property is to do a fetch of the object based on the UUID every time it is needed. Is this something that one should never worry about?
Hello Developers,
So I am having a problem, I wanted to do some computation after I have called context.save() but looking at context.changedModelsArray i see that there is no models that have changed. I have also checked insertedModelsArray and deletedModelsArray and all they're empty. Does swiftdata not support or keep track of the models being deleted/changed/inserted?
I'm using SwiftData to save title and images.
When I delete the model, the fetched model count reduces. But in the settings - storage - myApp, the document and data does not change. I deleted all the models but its like 9GB left.
I followed the SwiftData example app provided by Apple as much as possible.
I tried isAutosaveEnabled = false and put save() to every delete functions.
deleteRule = .cascade
In my recent endeavor, I aimed to introduce new Fetch Index Elements to the Core Data model of my iOS application. To achieve this, I followed a process of lightweight migration, detailed as follows:
Navigate to Editor > Add Model Version to create a new version of the data model.
Name the new version with a sequential identifier (e.g., MyAppModelV3.xcdatamodel) based on the naming convention of previous models.
Select the newly created version, MyAppModelV3.xcdatamodel, as the active model.
Mark this new version as the "Current" model in the Xcode properties panel on the right.
In the new version of the model, MyAppModelV3.xcdatamodel, and add the new Fetch Index Elements there. Also, insert "v3" in the Versioning Hash Modifier field of affected entity, to indicate this modification.
Upon reflection, I realized that creating a new version of the xcdatamodel might not have been necessary for this particular case. However, it appears to have caused no adverse effects on the application's functionality.
During testing, I executed the application in a simulated environment, initially running an older version of the app to inspect the database content with SQLite DB Browser. I then upgraded to the latest app version to verify that the migration was successfully completed without causing any crashes. Throughout this testing phase, I employed the -com.apple.CoreData.MigrationDebug 1 flag to monitor all SQL operations, ensuring that indexes were appropriately dropped and recreated for the affected entity.
Following thorough testing, I deployed the update to production. The majority of users were able to upgrade to the new app version seamlessly. However, a small fraction reported crashes at startup, indicated by the following error message:
Fatal error: Unresolved error Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration." UserInfo={NSUnderlyingError=0x2820ad3e0 {Error Domain=NSCocoaErrorDomain Code=134100 "The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store." UserInfo={metadata={ NSPersistenceFrameworkVersion = 1338; NSStoreModelVersionChecksumKey = "qcPf6+DfpsPrDQ3j1EVXcBIrFe1O0R6IKd30sJf4IrI="; NSStoreModelVersionHashes = { NSAttachment = {length = 32, ...
Strangely, the only way I could replicate this issue in the simulator was by running the latest version of the app followed by reverting to an older version, a scenario unlikely to occur in a real-world setting. This raises the question: How could this situation arise with actual users, considering they would typically move from an old to a new version rather than the reverse?
I am reaching out to the community for insights or advice on this matter. Has anyone else encountered a similar problem during the Core Data migration process? How did you resolve it?
According to my experiments SwiftData does not work with model attributes of primitive type UInt64. More precisely, it crashes in the getter of a UInt64 attribute invoked on an object fetched from the data store.
With Core Data persistent UInt64 attributes are not a problem. Does anyone know whether SwiftData will ever support UInt64?
Hi,
I am developing a multi platform application using SwiftData.
Since a few days, when running the macOS version I cannot create the model container while on iOS everything is fine.
On macOS I receive the error :
Thread 1: Fatal error: Could not create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer)
The code that initialize the model container is :
let schema = Schema([
Account.self,
ABCategory.self
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
let container = try ModelContainer(for: schema, configurations: [modelConfiguration])
container.mainContext.undoManager = UndoManager()
return container
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}
var body: some Scene {
WindowGroup {
ContentView(accuBalanceModel: accuBalanceModel)
}
.modelContainer(sharedModelContainer)
//.modelContainer(for: [Account.self, ABCategory.self], inMemory: false, isUndoEnabled: true)
#if os (OSX)
//
// Remove the 'New Window' menu item.
//
.commands {
CommandGroup(replacing: CommandGroupPlacement.newItem) {
}
}
#endif
}
I can say that the model has no issues as it works when running on IOS and also, if I
change inMemory: false with inMemory: true the macOS version succeed in creating the model.
I can also say this is not a network issue as the Mac and the iOS device running the application are connected to the same box.
The Xcode version is Version 15.2 (15C500b)
Ios device where everything is fine : iPhone 11 OS 17.3.1 (21D61)
the Mac device : Mac mini M1 2020 : 14.0 (23A344)
Any advice to resolve that problem would be greatly appreciated.
Best Regards
Christophe Lestrade
Hi
I have an App that uses SwiftData + CloudKit as a private database to sync across users' devices. Is there a way to enable sharing and collaboration capabilities with other users by using Cloudkit + CoreData?
To reduce the complexity of the Shared Object Graph, I envision treating the object graph as an Object (Document). In this way, the cloud's implementation of the sharing DB is simplified. The App will take care of the integrity and security of the document.
Ideally, I would love this capability in a multi-peer-to-peer local network, but I have yet to find a Conflict-free Replicated Document library to use.
In summary, I want to use SwiftData for the CRUD operations in the data objects running in the local App and treat the Object Graph as a document for sharing with other users.
Any guidance or any code examples will be appreciated.
Thank you!