关闭 iCloud 并从无处不在的容器中删除项目

Posted

技术标签:

【中文标题】关闭 iCloud 并从无处不在的容器中删除项目【英文标题】:Turning off iCloud and remove items from the ubiquitous container 【发布时间】:2017-04-10 14:13:49 【问题描述】:

我的应用中有一个UISwitch 供用户打开/关闭iCloud。我想实现以下目标:当用户关闭 iCloud 时,无处不在的容器中的所有内容都将被删除并复制到本地目录作为备份。但是,一旦文件从普遍存在的容器中删除,iCloud 服务器上的副本也会被删除。这基本上清除了 iCloud 上的所有内容。

我有以下问题:

    如何在不影响 iCloud 服务器上的副本的情况下删除无处不在的容器上的文件?

    在禁用 iCloud 之前从普遍存在的容器中删除文件的最佳或标准做法是什么?

    iCloud 在初始化/启用后是否可以完全禁用?

谢谢。

【问题讨论】:

【参考方案1】:

在阅读了Apple的文档和其他人的建议后,这是我的理解。我不是 100% 确定它们是否正确。欢迎评论和指正:

    在 ubiquity 容器中添加或删除的任何内容都将与 iCloud 服务器同步。该应用程序无法控制这一点。

    一旦用户在“设置”应用中启用了 iCloud 文档存储,应用就无法将其禁用。该应用的职责是提供 UI(假设为 UISwitch)以让用户指明他们希望其文档与应用的 iCloud 同步的位置。

    如果用户通过在应用中(不是在设置中)关闭UISwitch来关闭iCloud,应用应该做的是停止查询元数据,停止收听NSMetadataQueryDidUpdateNotification,停止访问文件在无处不在的容器中(如上面的 crizzis 所述)。如果稍后用户再次打开 iCloud,则 ubiquity 容器中的文件将自动与 iCloud 同步,除非发生未解决的冲突,否则无需手动合并。

【讨论】:

嗨,马克。您对此的理解有什么进一步的进展吗?今晚处理同样的事情......谢谢。 从您的(仍然非常好的)答案中我不清楚的是 - 一旦我们发现用户关闭了 iCloud,我们是否可以从普遍存在的容器中获取文件(如果应用程序被终止,下次用户打开应用程序时等),并将它们保存在本地?这样,保存在 iCloud 中的备份可以移动到本地存储,并且当用户在“设置”应用中关闭 iCloud 时,应用仍然可以访问这些备份。这是否符合您的回答,还是我们不能在那时获取这些文件?【参考方案2】:
    使用evictUbiquitousItem(at url:) 参见第 1 点。不过,我不确定您为什么要这样做。你不能在开关关闭的那一刻就停止访问本地副本吗? 我认为不能以编程方式禁用它。积极的一面是,如果您想让用户禁用 iCloud,它已经存在。 iCloud 应该通过 Settings 应用程序禁用,您真正需要做的就是通过收听NSUbiquityIdentityDidChangeNotification 在应用程序中处理这个事实

更新

Amin Negm-Awad 建议 evictUbiquitousItem(at url:) 强制重新加载,因此不会永久删除本地副本。但是,出于好奇,我做了一些测试,并没有发现情况如此。以下测试:

func runTest(ubiURL: URL) 
    self.query.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
    self.query.predicate = NSPredicate(format: "%K like '*'", NSMetadataItemFSNameKey)
    NotificationCenter.default.addObserver(self, selector: #selector(self.metadataQueryDidUpdate(_:)), name: NSNotification.Name.NSMetadataQueryDidUpdate, object: self.query)
    self.query.start()
    self.query.enableUpdates()
    let fileURL = ubiURL.appendingPathComponent("Documents/file.txt")
    FileManager.default.createFile(atPath: fileURL.path, contents: "Hello".data(using: .utf8))
    do 
        try FileManager.default.startDownloadingUbiquitousItem(at: fileURL)
     catch 
        print("startDownloadingUbiquitousItem: \(error.localizedDescription)")
    


var updateCount = 0

func metadataQueryDidUpdate(_ notification: Notification) 
    print("######################")
    print("update #\(updateCount)")

    for file in query.results as! [NSMetadataItem] 
        guard let fileURL = file.value(forAttribute: NSMetadataItemURLKey) as? URL, let fileStatus = file.value(forAttribute: NSMetadataUbiquitousItemDownloadingStatusKey) as? String else 
            print("Invalid item!")
            return
        
        if fileStatus == NSMetadataUbiquitousItemDownloadingStatusCurrent 
            print("URL to evict: \(fileURL)")
            do 
                try FileManager.default.evictUbiquitousItem(at: fileURL)
                print("Eviction result: successful")
             catch 
                print("evictUbiquitousItem: \(error.localizedDescription)")
            
        
        print("File exists at URL: \(FileManager.default.fileExists(atPath: fileURL.path))")
    

    updateCount = updateCount + 1


产量:

ubiURL is file:///private/var/mobile/Library/Mobile%20Documents/iCloud~com~example~blabla3/
######################
update #0
URL to evict: file:///private/var/mobile/Library/Mobile%20Documents/iCloud~com~example~blabla3/Documents/file.txt
evictUbiquitousItem: The file “file.txt” couldn’t be saved in the folder “blabla”.
File exists at URL: true
######################
...
update #3
URL to evict: file:///private/var/mobile/Library/Mobile%20Documents/iCloud~com~example~blabla3/Documents/file.txt
Eviction result: successful
File exists at URL: true
######################
update #4
File exists at URL: false
(no further updates followed)

我认为远程文件不会最终出现在设备上,除非使用被驱逐文件的 URL 调用 startDownloadingUbiquitousItemAtUrl:。不过,不确定是否可以依赖这种行为。

【讨论】:

我认为,evictUbiquitousItemAtURL:error: 不会永久删除本地副本,而是强制重新加载。我认为根本不可能删除本地副本,同时在 iCloud 中仍然有一个版本。

以上是关于关闭 iCloud 并从无处不在的容器中删除项目的主要内容,如果未能解决你的问题,请参考以下文章

NSFileWrapper 从 iCloud 失败并从本地目录工作

如何在我的无处不在的容器中获取所有可用的持久存储?

在 iOS 8 中将应用程序的无处不在的容器暴露给 iCloud Drive

删除 iCloud 容器内容

我可以从 iCloud 容器中的生产环境中删除记录类型吗?

来自 WKWebview 的 iCLoud 文档选择器关闭容器视图