如何告诉iOS从iCloud Drive下载文件并获得进度反馈

时间:2022-12-14 19:55:51

I am using the UIDocumentPicker to select a file but if it's large it can take a while to open and that is not a particularly good experience for users.

我正在使用UIDocumentPicker来选择一个文件,但如果它很大,它可能需要一段时间才能打开,这对用户来说不是特别好的体验。

I have looked at the iCloud programming guide from Apple and I cannot seem to figure out how to actually download a file and get some progress feedback, the documentation is just too vague. I know I am supposed to do something with NSMetadataItems, but there isn't much explaining actually how to get one and use it.

我查看了Apple的iCloud编程指南,我似乎无法弄清楚如何实际下载文件并获得一些进度反馈,文档太模糊了。我知道我应该对NSMetadataItems做一些事情,但实际上没有太多解释如何获得并使用它。

Can someone please explain it to me?

有人可以向我解释一下吗?

P.S. can someone with higher rep than me tag this post with UIDocumentPicker and iCloudDrive?

附:有没有比我更高的代表的人用UIDocumentPicker和iCloudDrive标记这篇文章?

2 个解决方案

#1


7  

To my knowledge, you can only retrieve progress feedback using the Ubiquitous Item Downloading Status Constants which provides only 3 states:

据我所知,您只能使用Ubiquitous Item Downloading Status Constants检索进度反馈,该常量只提供3种状态:

  • NSURLUbiquitousItemDownloadingStatusCurrent
  • NSURLUbiquitousItemDownloadingStatusCurrent
  • NSURLUbiquitousItemDownloadingStatusDownloaded
  • NSURLUbiquitousItemDownloadingStatusDownloaded
  • NSURLUbiquitousItemDownloadingStatusNotDownloaded
  • NSURLUbiquitousItemDownloadingStatusNotDownloaded

So you can't have a quantified progress feedback, only partial aka downloaded or not.

所以你不能有量化的进度反馈,只有部分也可以下载。

To do so, you need to prepare and start your NSMetadataQuery, add some observers and check the downloading status of your NSMetadataItem using the NSURLUbiquitousItemDownloadingStatusKey key.

为此,您需要准备并启动NSMetadataQuery,添加一些观察者并使用NSURLUbiquitousItemDownloadingStatusKey键检查NSMetadataItem的下载状态。

self.query = [NSMetadataQuery new];
self.query.searchScopes = @[ NSMetadataQueryUbiquitousDocumentsScope ];
self.query.predicate = [NSPredicate predicateWithFormat:@"%K like '*.yourextension'", NSMetadataItemFSNameKey];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidUpdate:) name:NSMetadataQueryDidUpdateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:nil];

[self.query startQuery];

Then,

然后,

- (void)queryDidUpdate:(NSNotification *)notification
{
    [self.query disableUpdates];

    for (NSMetadataItem *item in [self.query results]) {
        NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
        NSError *error = nil;
        NSString *downloadingStatus = nil;

        if ([url getResourceValue:&downloadingStatus forKey:NSURLUbiquitousItemDownloadingStatusKey error:&error] == YES) {
            if ([downloadingStatus isEqualToString:NSURLUbiquitousItemDownloadingStatusNotDownloaded] == YES) {
                // Download
            }
            // etc.
        }
    }

    [self.query enableUpdates];
}

#2


1  

Progress feedback from an NSMetadataQuery happens through notifications. The update frequency is once per second per default (can be changed by setting notificationBatchingInterval). The updated objects are encapsulated in the userInfo dict of the notification as arrays of NSMetadataItem. Download feedback is encapsultaed in the key NSMetadataUbiquitousItemPercentDownloadedKey of each item. Since the arrays are internally mutable, we need to tell NSMetadataQuery to disable updates while we enumerate the results. This is important, otherwise strange crashes will occur.

来自NSMetadataQuery的进度反馈通过通知发生。更新频率默认为每秒一次(可以通过设置notificationBatchingInterval来更改)。更新的对象封装在通知的userInfo dict中,作为NSMetadataItem的数组。下载反馈包含在每个项目的关键NSMetadataUbiquitousItemPercentDownloadedKey中。由于数组是内部可变的,我们需要告诉NSMetadataQuery在枚举结果时禁用更新。这很重要,否则会发生奇怪的崩溃。

A typical implementation might look like this:

典型的实现可能如下所示:

- (void) queryDidUpdate:(NSNotification *)notification {

[self.mdQuery disableUpdates];// we don't want to receive a new update while we still process the old one

NSArray *addedItems     = notification.userInfo[NSMetadataQueryUpdateAddedItemsKey];
NSArray *remItems       = notification.userInfo[NSMetadataQueryUpdateRemovedItemsKey];
NSArray *changedItems   = notification.userInfo[NSMetadataQueryUpdateChangedItemsKey];

// add
for (NSMetadataItem *mdItem in addedItems) {
    NSURL *url          = [mdItem valueForKey:NSMetadataUbiquitousItemURLInLocalContainerKey];
    // do something...
}
// remove
for (NSMetadataItem *mdItem in remItems) {
    NSURL *url          = [mdItem valueForKey:NSMetadataUbiquitousItemURLInLocalContainerKey];
    // do something...
}
// change
for (NSMetadataItem *mdItem in changedItems) {
    NSURL *url          = [mdItem valueForKey:NSMetadataUbiquitousItemURLInLocalContainerKey];
        // uploading
        BOOL uploading  = [(NSNumber *)[mdItem valueForKey:NSMetadataUbiquitousItemIsUploadingKey] boolValue];
        if (uploading) {
            NSNumber *percent   = [mdItem valueForKey:NSMetadataUbiquitousItemPercentUploadedKey];
            cell.progressView.progress = percent.floatValue;
            // do something...
        }
        // downloading
        BOOL downloading    = [(NSNumber *)[mdItem valueForKey:NSMetadataUbiquitousItemIsDownloadingKey] boolValue];
        if (downloading) {
            NSNumber *percent   = [mdItem valueForKey:NSMetadataUbiquitousItemPercentDownloadedKey];
            cell.progressView.progress = percent.floatValue;
            // do something...
        }
    }
[self.mdQuery enableUpdates];
}

#1


7  

To my knowledge, you can only retrieve progress feedback using the Ubiquitous Item Downloading Status Constants which provides only 3 states:

据我所知,您只能使用Ubiquitous Item Downloading Status Constants检索进度反馈,该常量只提供3种状态:

  • NSURLUbiquitousItemDownloadingStatusCurrent
  • NSURLUbiquitousItemDownloadingStatusCurrent
  • NSURLUbiquitousItemDownloadingStatusDownloaded
  • NSURLUbiquitousItemDownloadingStatusDownloaded
  • NSURLUbiquitousItemDownloadingStatusNotDownloaded
  • NSURLUbiquitousItemDownloadingStatusNotDownloaded

So you can't have a quantified progress feedback, only partial aka downloaded or not.

所以你不能有量化的进度反馈,只有部分也可以下载。

To do so, you need to prepare and start your NSMetadataQuery, add some observers and check the downloading status of your NSMetadataItem using the NSURLUbiquitousItemDownloadingStatusKey key.

为此,您需要准备并启动NSMetadataQuery,添加一些观察者并使用NSURLUbiquitousItemDownloadingStatusKey键检查NSMetadataItem的下载状态。

self.query = [NSMetadataQuery new];
self.query.searchScopes = @[ NSMetadataQueryUbiquitousDocumentsScope ];
self.query.predicate = [NSPredicate predicateWithFormat:@"%K like '*.yourextension'", NSMetadataItemFSNameKey];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidUpdate:) name:NSMetadataQueryDidUpdateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:nil];

[self.query startQuery];

Then,

然后,

- (void)queryDidUpdate:(NSNotification *)notification
{
    [self.query disableUpdates];

    for (NSMetadataItem *item in [self.query results]) {
        NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
        NSError *error = nil;
        NSString *downloadingStatus = nil;

        if ([url getResourceValue:&downloadingStatus forKey:NSURLUbiquitousItemDownloadingStatusKey error:&error] == YES) {
            if ([downloadingStatus isEqualToString:NSURLUbiquitousItemDownloadingStatusNotDownloaded] == YES) {
                // Download
            }
            // etc.
        }
    }

    [self.query enableUpdates];
}

#2


1  

Progress feedback from an NSMetadataQuery happens through notifications. The update frequency is once per second per default (can be changed by setting notificationBatchingInterval). The updated objects are encapsulated in the userInfo dict of the notification as arrays of NSMetadataItem. Download feedback is encapsultaed in the key NSMetadataUbiquitousItemPercentDownloadedKey of each item. Since the arrays are internally mutable, we need to tell NSMetadataQuery to disable updates while we enumerate the results. This is important, otherwise strange crashes will occur.

来自NSMetadataQuery的进度反馈通过通知发生。更新频率默认为每秒一次(可以通过设置notificationBatchingInterval来更改)。更新的对象封装在通知的userInfo dict中,作为NSMetadataItem的数组。下载反馈包含在每个项目的关键NSMetadataUbiquitousItemPercentDownloadedKey中。由于数组是内部可变的,我们需要告诉NSMetadataQuery在枚举结果时禁用更新。这很重要,否则会发生奇怪的崩溃。

A typical implementation might look like this:

典型的实现可能如下所示:

- (void) queryDidUpdate:(NSNotification *)notification {

[self.mdQuery disableUpdates];// we don't want to receive a new update while we still process the old one

NSArray *addedItems     = notification.userInfo[NSMetadataQueryUpdateAddedItemsKey];
NSArray *remItems       = notification.userInfo[NSMetadataQueryUpdateRemovedItemsKey];
NSArray *changedItems   = notification.userInfo[NSMetadataQueryUpdateChangedItemsKey];

// add
for (NSMetadataItem *mdItem in addedItems) {
    NSURL *url          = [mdItem valueForKey:NSMetadataUbiquitousItemURLInLocalContainerKey];
    // do something...
}
// remove
for (NSMetadataItem *mdItem in remItems) {
    NSURL *url          = [mdItem valueForKey:NSMetadataUbiquitousItemURLInLocalContainerKey];
    // do something...
}
// change
for (NSMetadataItem *mdItem in changedItems) {
    NSURL *url          = [mdItem valueForKey:NSMetadataUbiquitousItemURLInLocalContainerKey];
        // uploading
        BOOL uploading  = [(NSNumber *)[mdItem valueForKey:NSMetadataUbiquitousItemIsUploadingKey] boolValue];
        if (uploading) {
            NSNumber *percent   = [mdItem valueForKey:NSMetadataUbiquitousItemPercentUploadedKey];
            cell.progressView.progress = percent.floatValue;
            // do something...
        }
        // downloading
        BOOL downloading    = [(NSNumber *)[mdItem valueForKey:NSMetadataUbiquitousItemIsDownloadingKey] boolValue];
        if (downloading) {
            NSNumber *percent   = [mdItem valueForKey:NSMetadataUbiquitousItemPercentDownloadedKey];
            cell.progressView.progress = percent.floatValue;
            // do something...
        }
    }
[self.mdQuery enableUpdates];
}