IceCream
IceCream copied to clipboard
Versioning records
This one is more of a brainstorm. Here's the problem:
The Problem
- A user has my flashcard app (for example) installed on an iPad and iPhone.
- I release an update, allowing users to add images to cards.
- They update their iPhone app and add some images.
- They continue to use their iPad app, without updating.
- The iPad version successfully synchronizes the updated cards, but of course, does not pull the images out of the record, because it does not yet know about them.
- The iPad user makes updates to these cards, which synchronizes them back up to the server, effectively deleting the images.
One Possible Solution
I'm not sure the best way to fix this. It is clearly one of the more complicated problems, with regards to multidevice asynchronous syncing. There's a blog post here https://www.toptal.com/ios/sync-data-across-devices-with-cloudkit, which suggests adding a version to each record.
If our local app encounters a higher version than it knows how to deal with—suggesting that the user has updated the app elsewhere—then we can abort all synchronization until the user updates their version of the app.
@dbmrq @caiyue1993 Have either of you under this problem before? Any thoughts? :)
Nice catch! The versioning idea sounds good to me.
I have seen this versioning method before - but for the life of me I can not remember where.
Anyhow. I think adding a version number is extremely sensible and will be a common issue - it's not an edge case. Thinking about myself I know we have 4 iPads in the house and I bet none of them share the same iOS version number.
Thinking about the implementation...... how would you generate or configure the version number? Could that be the Realm migration number?
@ianbradbury-bizzibody I'm thinking something along the lines of:
- A
static let version : Int
on eachSyncable
class. The developer should increment this whenever the record structure changes in a way that would break things given the situation described above. - Sync Engine Changes
changesOp.recordChangedBlock = { [weak self] record in
/// The Cloud will return the modified record since the last zoneChangesToken, we need to do local cache here.
/// Handle the record:
guard let self = self else { return }
guard let syncObject = self.syncObjects.first(where: { $0.recordType == record.recordType }) else { return }
/// NEW CODE
if let version = record["version"], version > syncObject.version {
// OMG! ABORT! CUT POWER TO THE SYNC ENGINE! WE'RE SINKING!
}
/// END
syncObject.add(record: record)
}
- Then, don't sync until the user updates the app?
@caiyue1993, by the way, is there a test suite somewhere? If not, I might try to create one. It would be great to be able to test weird edge cases like this.
Good idea!
has anyone started working on this already? 😀
Do we have a timeframe?
Any luck getting a fix / workaround for this issue? This is actually a big problem I'm facing as well.