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.
I added the following methods to my application, based on some Apple-provided code, with a couple tweaks:
The download methods:
- (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];
}
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
So for whatever reason:
- The download for the file starts without error
- 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.
- I'm stuck in the loop forever, even though the file size changes in between checks.
What am I doing wrong?
See Question&Answers more detail:os