【问题标题】:How can I delete a file from iCloud without downloading it to the device first?如何在不先将文件下载到设备的情况下从 iCloud 删除文件?
【发布时间】:2015-04-12 22:39:36
【问题描述】:

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

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

[[[NSFileCoordinator alloc] initWithFilePresenter:nil]
coordinateWritingItemAtURL:documentURL
                  options:NSFileCoordinatorWritingForDeleting
         writingItemAtURL:previewURL
                  options:NSFileCoordinatorWritingForDeleting
                    error:&error
               byAccessor:^(NSURL *newDocumentURL, NSURL *newPreviewURL){

    // Fails with "No such file" error if not yet downloaded from iCloud:
    [[NSFileManager defaultManager] removeItemAtURL:newDocumentURL error:&error];
    [[NSFileManager defaultManager] removeItemAtURL:newPreviewURL  error:&error];
}];

完整的错误:

Error Domain=NSCocoaErrorDomain Code=4 "The operation couldn’t be completed. 
(Cocoa error 4.)" UserInfo=0x14e82930 {NSUnderlyingError=0x14e69220 
"The operation couldn’t be completed. No such file or directory",

【问题讨论】:

    标签: ios cocoa-touch icloud nsfilemanager


    【解决方案1】:

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

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

    我错过的一点是,您必须使用为删除而创建的 NSFileAccessIntent 对象的 URL 调用 fileManager.removeItemAtURL,而不是您可以从中访问的普通 URL你的NSMetadataQueryItem

    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)
        }
    }
    

    如果您想删除多个项目:

    for url in urlsToDelete {
        removeFile(at: url)
    }
    

    【讨论】:

      【解决方案2】:

      如果您只需要删除一个文件,请使用另一个 NSFileCoordinator coordinateWritingItemAtURL(在访问器块中具有单个 newURL 参数的那个)。

      如果需要批量删除,则创建一个NSFileAccessIntent数组,使用NSFileCoordinator的coordinateAccessWithIntents。

      例子:

      - ( void )deleteItemsAtURLs: ( NSArray * )urls queue: ( NSOperationQueue * )queue
      {
          //assuming urls is an array of urls to be deleted
          NSFileCoordinator   * coordinator;
          NSMutableArray      * writingIntents;
          NSURL               * url;
      
          writingIntents = [ NSMutableArray arrayWithCapacity: urls.count ];
      
          for( url in urls )
          {
              [ writingIntents addObject: [ NSFileAccessIntent writingIntentWithURL: url options: NSFileCoordinatorWritingForDeleting ] ];
          }
      
          coordinator = [ [ NSFileCoordinator alloc ] initWithFilePresenter: nil ];
      
          [ coordinator coordinateAccessWithIntents: writingIntents
                                              queue: queue
                                         byAccessor: ^( NSError * error )
           {
               if( error )
               {
                   //handle
                   return;
               }
               NSFileAccessIntent * intent;
      
               error = nil;
      
               for( intent in writingIntents )
               {
                   [ [ NSFileManager defaultManager ] removeItemAtURL: intent.URL error: &error ];
                   if( error )
                   {
                       //handle
                   }
               }
           }];
      }
      

      【讨论】:

      • 确实,一一删除确实有效。所以我猜这是 NSFileCoordinator 尝试一次删除 2 个文件时的错误?
      • 你使用的方法不是批量删除,而是后续操作。对于批处理操作,请参阅我给您的示例。不过,不完全确定为什么只删除 2 项是行不通的。
      • 为什么2012年的答案包含iOS8 API?如果有 iOS7 兼容的解决方案就好了。
      • 这解决了我删除另一个设备创建的 iCloud 文件的问题。 NSFileManager 无法自行完成——需要包装在 NSFileCoordinator 中。 +1
      猜你喜欢
      • 2012-06-12
      • 1970-01-01
      • 1970-01-01
      • 2020-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      • 1970-01-01
      相关资源
      最近更新 更多