如何从 iCloud 删除文件而不先将其下载到设备?

Mar*_*ark 4 cocoa-touch nsfilemanager ios icloud

我有一个基本的 iOS 应用程序,可以显示文档列表。我正在尝试删除文档,但注意到如果文档尚未从 iCloud 下载到设备,下面的代码会失败并显示“没有此类文件或目录” 。

\n\n

文档可能非常大(40MB),我希望避免下载文档只是为了删除它(这会占用用户数据计划的时间和带宽)。这有可能吗?

\n\n
[[[NSFileCoordinator alloc] initWithFilePresenter:nil]\ncoordinateWritingItemAtURL:documentURL\n                  options:NSFileCoordinatorWritingForDeleting\n         writingItemAtURL:previewURL\n                  options:NSFileCoordinatorWritingForDeleting\n                    error:&error\n               byAccessor:^(NSURL *newDocumentURL, NSURL *newPreviewURL){\n\n    // Fails with "No such file" error if not yet downloaded from iCloud:\n    [[NSFileManager defaultManager] removeItemAtURL:newDocumentURL error:&error];\n    [[NSFileManager defaultManager] removeItemAtURL:newPreviewURL  error:&error];\n}];\n
Run Code Online (Sandbox Code Playgroud)\n\n

完整错误:

\n\n
Error Domain=NSCocoaErrorDomain Code=4 "The operation couldn\xe2\x80\x99t be completed. \n(Cocoa error 4.)" UserInfo=0x14e82930 {NSUnderlyingError=0x14e69220 \n"The operation couldn\xe2\x80\x99t be completed. No such file or directory",\n
Run Code Online (Sandbox Code Playgroud)\n

Dan*_*sko 6

注意:Apple 曾经有一些示例代码来说明这一点,但遗憾的是它已被删除。

正如答案中所指出的,您需要循环调用此方法,因为您需要NSFileCoordinator为每个要删除的文件单独调用该方法。

我错过的一点是,您必须使用您创建的用于删除的对象fileManager.removeItemAtURL的 URL进行调用,而不是使用您从.NSFileAccessIntentURLNSMetadataQueryItem

func removeFile(at url: URL, completionHandler: ((Error?) -> Void)? = nil) {
    // `url` may be a security scoped resource.
    let successfulSecurityScopedResourceAccess = url.startAccessingSecurityScopedResource()

    let fileCoordinator = NSFileCoordinator()
    let writingIntent = NSFileAccessIntent.writingIntent(with: url, options: .forDeleting)
    fileCoordinator.coordinate(with: [writingIntent], queue: backgroundQueue) { (accessError) in
        if accessError != nil {
            completionHandler?(accessError)
            return
        }

        let fileManager = FileManager()
        var error: Error?
        do {
            try fileManager.removeItem(at: writingIntent.url)
        }
        catch let fileError {
            error = fileError
        }
        if successfulSecurityScopedResourceAccess {
            url.stopAccessingSecurityScopedResource()
        }

        completionHandler?(error)
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想删除多个项目:

for url in urlsToDelete {
    removeFile(at: url)
}
Run Code Online (Sandbox Code Playgroud)