【问题标题】:iCloud NSDocument save warnings - caused by lastUsedDate file attribute?iCloud NSDocument 保存警告 - 由 lastUsedDate 文件属性引起?
【发布时间】:2018-07-18 07:28:31
【问题描述】:

我有一个应用在 OS X 上使用 NSPersistentDocument(没有自动保存),在 iOS 上使用UIDocument(也没有自动保存)。文件表示是二进制核心存储。此应用自 iOS 7 + macOS 10.10 以来一直运行良好。

如果我在 OS X 10.13 上打开一个文档,而另一台设备(macOS 10.13 或 iOS 11)打开同一个文件,在下次保存时我会收到警告 “此文档的文件已被另一个应用程序更改您打开或保存了它。”。该警告是虚假的,因为仅在另一台设备上发生了打开 - 而不是保存。

在寻找此通知的可能原因时,我注意到当在一台设备上打开 iCloud 文件时,会更新名为 com.apple.lastuseddate#PS 的扩展属性。我已确认此扩展属性在 iOS 11 和 macOS 10.13 上均已更新。此扩展属性似乎未在早期版本的 iOS 或 macOS 中使用。我想知道文件元数据的更新是否触发了这个虚假警告。

(我怀疑这个属性可能与 iOS 11 上的 NSFileProvider 有关,因为在 macOS 10.13 上有一个新方法 setLastUsedDate:forItemIdentifier:completionHandler:FinderSync setLastUsedDate:forItemWithURL:completion: 也是新的。)

我的问题是 - 其他人看到这种新行为了吗?会不会给其他人带来这么烦人的副作用?

【问题讨论】:

    标签: icloud nsdocument uidocument nspersistentdocument apfs


    【解决方案1】:

    我已经进一步研究了这个问题。我已经确定了似乎正在发生的事情,以及解决方法。注意这仅适用于NSPersistentDocument - 没有自动保存。

    首先是关于文件时间戳和文件系统类型的重要说明。 HFS+ 时间戳的分辨率为一秒。 APFS timestamps have a resolution of 1 nanosecond.

    当 OS X 应用程序的 iCloud 容器迁移到 APFS 时,我的问题才开始显现。

    这是一个典型的序列(我使用 OS X 和 iOS 作为示例设备 - 但无论“其他”iCloud 连接设备的操作系统类型如何,都会发生相同的序列):

    1. 在 OS X 上的 iCloud 应用容器中打开一个文件。
    2. 进行更改并将更改保存到文件中,此时APFS 上的文件修改日期将包含小数秒部分。
    3. 在另一台设备上打开相同的文件 - 比如 iOS(在允许 iCloud 传播更改之后)。在 iOS 上打开文件的修改日期已截断小数秒部分。
    4. 不久之后,回到 OS X,最近保存的文件的修改日期将被截断小数秒部分(由我无法控制的 iCloud 进程 - 此时调用 presentedItemDidChange) .
    5. 如果另一个更改保存到 OS X 文件,则会出现更改警告“此文档的文件在您打开或保存后已被另一个应用程序更改。”。这是因为上次保存的 NSDocument self.fileModificationDate(包含小数秒部分)与文件修改日期(已截断小数部分)不匹配。

    含义是:

    • 当 iCloud 在主机之间交换时间戳元数据时,分辨率以秒为单位。
    • 当打开文件并将时间戳元数据传送到其他设备时,它是截断形式。它还会写回到最后写入文件的设备上的文件中。

    我采用的解决方法(这只是必要的,因为我使用 NSPersistentDocument 没有自动保存)是将 self.fileModificationDate 设置为小数秒截断版本(是的,它是读写),如果且仅如果 self.fileModificationDate 匹配忽略小数秒的文件修改日期。如果这样做了,则不会出现警告 - 并且不会造成任何伤害(因为文件没有被修改):

    // saving file changes
    
    NSDate *modDate = nil;
    [self.fileURL getResourceValue:&modDate forKey:NSURLContentModificationDateKey error:NULL];
    
    if (modDate && self.fileModificationDate) {
        NSTimeInterval delta = [modDate timeIntervalSinceDate:self.fileModificationDate];
        if (fabs(delta) > 0.0 && [modDate ss_isEqualToDateInSeconds:self.fileModificationDate])
            self.fileModificationDate = modDate.ss_dateWithDateInSeconds;
    }
    
    [self saveDocumentWithDelegate:self
                   didSaveSelector:@selector(documentSaved:didSave:contextInfo:)
                       contextInfo:nil];
    

    正如我一开始所说的——令人惊讶的行为。如果它被记录在案,那就太好了。因为我对NSDocument的使用不规范,不知道别人会不会有这个问题。

    【讨论】:

    • NSPersistentDocument 支持自动保存。至少它对我有用。
    • 伟大的调查。不过,我同意 Dirk 的观点,NSPersistentDocument 支持 autoSavesInPlace(只需覆盖返回 true 的方法)。
    • 谢谢@vomi。更正了我的答案,以免认为自动保存不起作用。我需要更多的控制权。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    • 1970-01-01
    • 2020-04-20
    • 2017-12-24
    • 2011-07-30
    相关资源
    最近更新 更多