I have an app that uses NSPersistentDocument (without autosaving) on OS X and UIDocument (also without autosaving) on iOS. The file representation is Binary Core Storage. This app has been working fine since iOS 7 + macOS 10.10.
If I open a document on OS X 10.13, and another device (macOS 10.13 or iOS 11) opens the same file, on the next save I get a warning "This document's file has been changed by another application since you opened or saved it.". The warning is spurious, because only an open has occured on another device - not a save.
In looking for a possible reason for this notification, I notice that when an iCloud file open occurs on one device, an extended attribute named com.apple.lastuseddate#PS is updated. I have confirmed this extended attribute is updated on both iOS 11 and macOS 10.13. This extended attribute doesn't appear to have been used in prior versions of iOS or macOS. I wonder if the updating of file metadata is triggering this spurious warning.
(I suspect this attribute may related to NSFileProvider on iOS 11 as there is a new method setLastUsedDate:forItemIdentifier:completionHandler: and FinderSync on macOS 10.13 as setLastUsedDate:forItemWithURL:completion: is also new.)
My question is - do others see this new behavior? Is it causing others such annoying side effects?
I have studied this problem further. I have determined what seems to be going on, and also workaround. NOTE this only applies to
NSPersistentDocument- without autosaving.Firstly an important note on file timestamps and file system type.
HFS+timestamps have a resolution on one second.APFStimestamps have a resolution of 1 nanosecond.My problems only started to manifest itself when the OS X App's iCloud container was migrated to
APFS.Here is a typical sequence (I've used OS X and iOS as example devices - but the same sequence happens regardless OS type for the 'other' iCloud connected device):
APFSwill have a fractional second component.presentedItemDidChangeis called at this time).NSDocumentself.fileModificationDatefrom the last save (which contains a fractional seconds component) and the file modification date (which has had the fractional seconds component truncated).The implications are:
The workaround I have employed (which is only necessary because I am using
NSPersistentDocumentwithout autoSaving) is to setself.fileModificationDateto the fractional seconds truncated version (yes it is read-write), if and only ifself.fileModificationDatematches the file modification date ignoring fractional seconds. If this is done, the warning doesn't appear - and no harm is done (as the file had not been modified):As I said at the outset — surprising behaviour. It would be nice if it was documented. Because my use of
NSDocumentis non-standard, I don't know if others may have this problem.