I’m building an app that edits files in iCloud and uses an NSFilePresenter to monitor changes.
When a conflict occurs, the system calls presentedItemDidGain(_:).
In that method, I merge the versions by reading the current (canonical) version using NSFileVersion.currentVersionOfItem(at:) and the conflicting ones using NSFileVersion.unresolvedConflictVersionsOfItem(at:).
This generally works, but sometimes, if two devices edit the same file at the same time, each device sees its own local version as the current one. For example:
Device A writes fileVerA (slightly later in real time)
Device B writes fileVerB
On Device A all works fine, currentVersionOfItem returns fileVerA, as expected, and unresolvedConflictVersionsOfItem returns [fileVerB].
But on Device B, currentVersionOfItem returns fileVerB!? And unresolvedConflictVersionsOfItem returns the same, local file [fileVerB], without any hint of the other conflicting version, fileVerA.
Later, the newer version from the Device A arrives on Device B as a normal, non-conflicting update via presentedItemDidChange(_:).
This seems to contradict Apple’s documentation: “The currentVersionOfItemAtURL: method returns an NSFileVersion object representing what’s referred to as the current file; the current file is chosen by iCloud on some basis as the current “conflict winner” and is the same across all devices.”
Is this expected behavior, or a bug in how iCloud reports file versions?
fileVerA not existing on device B explains why currentVersionOfItem returns fileVerB. But as you've pointed out and the documentation mentions , presentedItemDidGain(_:) is supposed to be called after a new version was added, which does seem to conflict with your observation. I’d hence suggest that you file a feedback report – If you do so, please share your report ID here.
In presentedItemDidGain I check if the URL passed in is in a conflict state by using 'newVersionURL.isConflict', and it returns true, and then I run the merge. Is this the right way to check for a pending conflict?
Yes, the above flow sounds right, assuming presentedItemDidGain is called at the documented timing.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.