使用For循环时,文档无法上传到iCloud - iOS


I am attempting to upload a local folder full of documents to a remote iCloud folder. I wrote this method to loop through the array of files in the local folder, check if they already exist, and if they don't exist upload them to iCloud. Note- this code is being executed on the background thread not the main thread.

我正在尝试将一个装满文档的本地文件夹上传到远程iCloud文件夹。我编写了这个方法来遍历本地文件夹中的文件数组,检查它们是否已经存在,如果它们不存在,则将它们上传到iCloud。注意 - 此代码正在后台线程而不是主线程上执行。

//Get the array of files in the local documents directory
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSArray *localDocuments = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];

//Compare the arrays then upload documents not already existent in iCloud
for (int item = 0; item < [localDocuments count]; item++) {
    //If the file does not exist in iCloud, upload it
     if (![[iCloud previousQueryResults] containsObject:[localDocuments objectAtIndex:item]]) {
          NSLog(@"Uploading %@ to iCloud...", [localDocuments objectAtIndex:item]);
          //Move the file to iCloud
          NSURL *destinationURL = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil] URLByAppendingPathComponent:[NSString stringWithFormat:@"Documents/%@",[localDocuments objectAtIndex:item]]];
          NSError *error;
          NSURL *directoryURL = [[NSURL alloc] initWithString:[documentsDirectory stringByAppendingPathComponent:[localDocuments objectAtIndex:item]]];
          BOOL success = [[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:directoryURL destinationURL:destinationURL error:&error];
          if (success == NO) {
              //Determine Error
     } else {
     } }

When I run this code the For Loop works fine - I use NSLog statements to find out which file it is uploading - and every file stored locally that isn't already in iCloud is supposed to start uploading. After the For Loop is finished I check which documents are now in iCloud using developer.icloud.com. Only one file (an sqlite file that my app keeps making but never uses) out of the many stored locally uploads to iCloud. Why would only one file upload when using for loops?

当我运行此代码时,For循环工作正常 - 我使用NSLog语句找出它正在上传的文件 - 并且本地存储的每个尚未在iCloud中的文件应该开始上传。完成For循环后,我使用developer.icloud.com检查iCloud中现在有哪些文档。在许多存储的本地上传到iCloud中只有一个文件(我的应用程序一直在制作但从不使用的sqlite文件)。为什么在使用for循环时只上传一个文件?

When I use the same code to upload individual files (without a For Loop) they upload to iCloud perfectly. Why would a For Loop hinder the uploading of files? Does this have to do with the For Loop continuing to the next line of code without waiting for the last process / line to finish executing? What's going on here?


EDIT: Usually when I upload large files to iCloud (without using a For Loop) I can see on the iCloud dev site that the file is Pending Upload almost instantly. I'm testing everything over WiFi and I've been waiting a while but nothing appears (except for the sqlite file).


EDIT: I also check for iCloud availability in a different method which then allows calls to this method if iCloud is available. I've also made sure to read over the documentation and watched the WWDC videos on Apple's website, however they are complex and don't provide much explanation for what I'm trying to do.


EDIT: After revising the code above (adding the error functionality), I now get this error message in the log:


Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)" UserInfo=0x1f5dd070 {NSUnderlyingError=0x208ad9b0 "The operation couldn’t be completed. (LibrarianErrorDomain error 2 - No source URL specified.)"}

This makes things even more confusing because one of the files uploads successfully, whereas the others do not.


1 个解决方案



OK, that last edit is useful. The error complains that the source URL (directoryURL in your code) is missing-- probably because it's nil. Why would it be nil? Because you're creating it wrong. You're using -[NSURL initWithString:], and the docs say that:

好的,最后一次编辑很有用。错误抱怨源URL(代码中的directoryURL)丢失 - 可能是因为它是零。为什么会是零?因为你错了。你正在使用 - [NSURL initWithString:],文档说:

This string must conform to URL format as described in RFC 2396. This method parses URLString according to RFCs 1738 and 1808.

此字符串必须符合RFC 2396中所述的URL格式。此方法根据RFC 1738和1808解析URLString。

You're passing in a file path, not a URL. If you pass NSURL something it doesn't recognize as a valid URL, it normally returns nil. It looks like NSURL will frequently produce a file URL anyway, but failure is the expected behavior here. From what I can tell it seems to work if the filename contains no spaces, but that's not documented and not something you could rely on.


What you should do is change the line where you initialize directoryURL to use something that accepts a file path. Something like:


NSURL *directoryURL = [NSURL fileURLWithPath:[documentsDirectory stringByAppendingPathComponent:[localDocuments objectAtIndex:item]]];

Also, make sure to verify that directoryURL is not nil, just in case.