下载iCloud文件的方法?很混乱? [英] Method for downloading iCloud files? Very confusing?

查看:973
本文介绍了下载iCloud文件的方法?很混乱?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中有基本的iCloud支持(同步更改,无处不在等),但到目前为止,一个重要的遗漏是缺乏对云中存在(或有变化)的文件的下载支持,但是与当前磁盘上的内容不同步。

I have basic iCloud support in my application (syncing changes, making ubiquitous, etc.), but one crucial omission so far has been the lack of "download" support for files that exist (or have changes) in the cloud, but are not in sync with what's currently on disk.

我根据一些Apple提供的代码向我的应用程序添加了以下方法,并进行了一些调整:

I added the following methods to my application, based on some Apple-provided code, with a couple tweaks:

下载方法:

- (BOOL)downloadFileIfNotAvailable:(NSURL*)file {
    NSNumber*  isIniCloud = nil;

    if ([file getResourceValue:&isIniCloud forKey:NSURLIsUbiquitousItemKey error:nil]) {
        // If the item is in iCloud, see if it is downloaded.
        if ([isIniCloud boolValue]) {
            NSNumber*  isDownloaded = nil;
            if ([file getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:nil]) {
                if ([isDownloaded boolValue])
                    return YES;

                // Download the file.
                NSFileManager*  fm = [NSFileManager defaultManager];
                NSError *downloadError = nil;
                [fm startDownloadingUbiquitousItemAtURL:file error:&downloadError];
                if (downloadError) {
                    NSLog(@"Error occurred starting download: %@", downloadError);
                }
                return NO;
            }
        }
    }

    // Return YES as long as an explicit download was not started.
    return YES;
}

- (void)waitForDownloadThenLoad:(NSURL *)file {
    NSLog(@"Waiting for file to download...");
    id<ApplicationDelegate> appDelegate = [DataLoader applicationDelegate];
    while (true) {
        NSDictionary *fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:[file path] error:nil];
        NSNumber *size = [fileAttribs objectForKey:NSFileSize];

        [NSThread sleepForTimeInterval:0.1];
        NSNumber*  isDownloading = nil;
        if ([file getResourceValue:&isDownloading forKey:NSURLUbiquitousItemIsDownloadingKey error:nil]) {
            NSLog(@"iCloud download is moving: %d, size is %@", [isDownloading boolValue], size);
        }

        NSNumber*  isDownloaded = nil;
        if ([file getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:nil]) {
            NSLog(@"iCloud download has finished: %d", [isDownloaded boolValue]);
            if ([isDownloaded boolValue]) {
                [self dispatchLoadToAppDelegate:file];
                return;
            }
        }

        NSNumber *downloadPercentage = nil;
        if ([file getResourceValue:&downloadPercentage forKey:NSURLUbiquitousItemPercentDownloadedKey error:nil]) {
            double percentage = [downloadPercentage doubleValue];
            NSLog(@"Download percentage is %f", percentage);
            [appDelegate updateLoadingStatusString:[NSString stringWithFormat:@"Downloading from iCloud (%2.2f%%)", percentage]];
        }
    }
}

以及启动的代码/检查下载:

And the code that starts/checks the downloads:

 if ([self downloadFileIfNotAvailable:urlToUse]) {
            // The file is already available. Load.
            [self dispatchLoadToAppDelegate:[urlToUse autorelease]];
        } else {
            // The file is downloading. Wait for it.
            [self performSelector:@selector(waitForDownloadThenLoad:) withObject:[urlToUse autorelease] afterDelay:0];
        }

据我所知上述代码看起来很好,但是当我在设备A上进行大量更改时,保存这些更改,然后打开设备B(以提示在设备B上下载)这是我在控制台中看到的:

As far as I can tell the above code seems fine, but when I make a large number of changes on Device A, save those changes, then open Device B (to prompt a download on Device B) this is what I see in the console:

2012-03-18 12:45:55.858 MyApp[12363:707] Waiting for file to download...
2012-03-18 12:45:58.041 MyApp[12363:707] iCloud download is moving: 0, size is 101575
2012-03-18 12:45:58.041 MyApp[12363:707] iCloud download has finished: 0
2012-03-18 12:45:58.041 MyApp[12363:707] Download percentage is 0.000000
2012-03-18 12:45:58.143 MyApp[12363:707] iCloud download is moving: 0, size is 101575
2012-03-18 12:45:58.143 MyApp[12363:707] iCloud download has finished: 0
2012-03-18 12:45:58.144 MyApp[12363:707] Download percentage is 0.000000
2012-03-18 12:45:58.246 MyApp[12363:707] iCloud download is moving: 0, size is 101575
2012-03-18 12:45:58.246 MyApp[12363:707] iCloud download has finished: 0
2012-03-18 12:45:58.246 MyApp[12363:707] Download percentage is 0.000000
2012-03-18 12:45:58.347 MyApp[12363:707] iCloud download is moving: 0, size is 177127
2012-03-18 12:45:58.347 MyApp[12363:707] iCloud download has finished: 0
2012-03-18 12:45:58.347 MyApp[12363:707] Download percentage is 0.000000
2012-03-18 12:45:58.449 MyApp[12363:707] iCloud download is moving: 0, size is 177127
2012-03-18 12:45:58.449 MyApp[12363:707] iCloud download has finished: 0
2012-03-18 12:45:58.450 MyApp[12363:707] Download percentage is 0.000000

因此无论如何:


  1. 文件下载启动时没有错误

  2. 文件下载状态的文件属性总是返回它没有下载,没有完成下载,进度是0%。

  3. 即使文件大小变化,我仍然永远停留在循环中es 在两次支票之间。

  1. The download for the file starts without error
  2. The file attributes for the file's download status always return that it's not downloading, has not finished downloading, and the progress is 0 percent.
  3. I'm stuck in the loop forever, even though the file size changes in between checks.

我做错了什么?

推荐答案

多年以后我仍然会遇到定期下载(虽然在其他答案中的一些解决方法之后更加罕见)下载文件的问题。所以,我联系了Apple的开发人员,要求进行技术审核/讨论,这就是我找到的。

Years later I am still experiencing periodic (though much more rare after some of the workarounds in other answers) issues downloading files. So, I contacted the developers at Apple asking for a technical review/discussion and here's what I found.

定期检查相同 NSURL ,即使您正在重新创建它,也不是检查状态的首选方法。我不知道它为什么不是 - 它似乎应该工作,但事实并非如此。相反,一旦开始下载文件,您应该使用 NSNotificationCenter 注册观察者以获取该下载的进度,并维护对该文件的查询的引用。这是提供给我的确切代码示例。我已经在我的应用程序中实现了它(通过一些特定于应用程序的调整),它似乎表现得更加恰当。

Periodically checking for the download status of the same NSURL, even if you're recreating it, is not the preferred method for checking the status. I don't know why it isn't - it seems like it should work, but it doesn't. Instead, once you begin to download the file, you should register an observer with NSNotificationCenter for the progress of that download, maintaining a reference to the query for that file. Here's the exact code sample that was provided to me. I've implemented it (with some app-specific tweaks) in my app, and it seems to be performing much more appropriately.

- (void)download:(NSURL *)url
{
    dispatch_queue_t q_default;
    q_default = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(q_default, ^{

        NSError *error = nil;
        BOOL success = [[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:url error:&error];
        if (!success)
        {
            // failed to download
        }
        else
        {
            NSDictionary *attrs = [url resourceValuesForKeys:@[NSURLUbiquitousItemIsDownloadedKey] error:&error];
            if (attrs != nil)
            {
                if ([[attrs objectForKey:NSURLUbiquitousItemIsDownloadedKey] boolValue])
                {
                    // already downloaded
                }
                else
                {
                    NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
                    [query setPredicate:[NSPredicate predicateWithFormat:@"%K > 0", NSMetadataUbiquitousItemPercentDownloadedKey]];
                    [query setSearchScopes:@[url]]; // scope the search only on this item

                    [query setValueListAttributes:@[NSMetadataUbiquitousItemPercentDownloadedKey, NSMetadataUbiquitousItemIsDownloadedKey]];

                    _fileDownloadMonitorQuery = query;

                    [[NSNotificationCenter defaultCenter] addObserver:self
                                                             selector:@selector(liveUpdate:)
                                                                 name:NSMetadataQueryDidUpdateNotification
                                                               object:query];

                    [self.fileDownloadMonitorQuery startQuery];
                }
            }
        }
    });
}

- (void)liveUpdate:(NSNotification *)notification
{
    NSMetadataQuery *query = [notification object];

    if (query != self.fileDownloadMonitorQuery)
        return; // it's not our query

    if ([self.fileDownloadMonitorQuery resultCount] == 0)
        return; // no items found

    NSMetadataItem *item = [self.fileDownloadMonitorQuery resultAtIndex:0];
    double progress = [[item valueForAttribute:NSMetadataUbiquitousItemPercentDownloadedKey] doubleValue];
    NSLog(@"download progress = %f", progress);

    // report download progress somehow..

    if ([[item valueForAttribute:NSMetadataUbiquitousItemIsDownloadedKey] boolValue])
    {
        // finished downloading, stop the query
        [query stopQuery];
        _fileDownloadMonitorQuery = nil;
    }
}

这篇关于下载iCloud文件的方法?很混乱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆