Reputation: 4152
I used as described in the Apple Docs NSMetadataQuery to search my iCloud file. I have only one file and I know its name. My problem is that sometimes this file doesn't exist (I guess because it has not yet been downloaded) and NSMetadataQuery is unable to find it.
Ever tried to force download with NSFileManager startDownloadingUbiquitousItemAtURL:error:
and it returns me an error. (Read EDIT)
My solution is that I created the file the first time, then I guess it exists and I open it with UIDocument. But It couldn't exist or it could be the first time the user opens the app. I can't be sure of these things. My first question is: if UIDocument opens the file, it means that it found the file somewhere. How could it use the file if it DOESN'T EXIST?
And then, second question: If I app which has to manage multiple files or files with unknown name. How can I find them if NSMetadataQuery doesn't work.
EDIT:
if startDownloadingUbiquitousItemAtURL
should be used to start downloading a file, how can I know when the file finished downloading (perhaps with a notification)? But, a more important thing: How can I download the file if is always says (removed original names)?
Error Domain=NSPOSIXErrorDomain Code=2 "The operation couldn’t be completed.
No such file or directory" UserInfo=0x166cb0 {
NSDescription=Unable to get real path for Path
'/private/var/mobile/Library/Mobile Documents/teamid~com~team~app/Documents/file.extension'
}
Upvotes: 6
Views: 7867
Reputation: 5817
I had a similar problem, metadataQueryDidUpdate and metadataQueryDidFinishGathering would fire, but the NSMetadataQuery's results would be empty. There was a provisioning profile problem that Xcode didn't tell me about until I attempted to test it on my device, where it failed, saying that my bundle identifier was invalid (it wasn't).
What fixed it for me was going into Preferences and clicking the Download All button for the provisioning profiles, and then doing a Clean in Xcode. Rebuild, run, and all my files showed up. Check in the developer portal to make sure none of your profiles are marked as Invalid. None of mine were, so it's not required to trigger this, but it can happen.
Not exactly scientific, but this did work for me.
Upvotes: 0
Reputation: 11
edo42, did you solve the issue? I had purchased a new 4S to go back to AT&T and I had backed up my first 4S and then restored from backup on new 4S and then this was happening for me.
Error Domain=NSPOSIXErrorDomain Code=2 "The operation couldn’t be completed. No such file or directory" UserInfo=0x448500 {NSDescription=Unable to get real path for Path '/private/var/mobile/Library/Mobile Documents/~UbiquitousDir~/Documents/MyDocument.ext'
(Works fine on my iPad 2)
Then I would do the NSMetadataQuery but then it comes back with no results. (Works on my iPad 2 just fine to see the document on iCloud).
I checked to see that the ubiquitous file exists but it is not there as the error suggest.
I tried using [fileMgr evictUbiquitousItemAtURL:ubiquitousDocumentsDir &error] and it does succeed. But when I try the NSMetadataQuery it still comes back with no results.
Hope this helps to figure what is wrong in both cases.
UPDATE: Ok there is a real problem with iCloud for this device that I restored from a backup:
Upvotes: 1
Reputation: 12004
I suggest the following load routine for iCloud files. It involves 4 steps:
NSPredicate *pred = [NSPredicate predicateWithFormat:@"NOT %K.pathExtension = '.'", NSMetadataItemFSNameKey];
will return all files which have an extension, like jpg, txt, dat etc.)Here is the code that exemplifies these four steps:
- (void)loadData:(NSMetadataQuery *)query {
// (4) iCloud: the heart of the load mechanism: if texts was found, open it and put it into _document; if not create it an then put it into _document
if ([query resultCount] == 1) {
// found the file in iCloud
NSMetadataItem *item = [query resultAtIndex:0];
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
MyTextDocument *doc = [[MyTextDocument alloc] initWithFileURL:url];
//_document = doc;
doc.delegate = self.viewController;
self.viewController.document = doc;
[doc openWithCompletionHandler:^(BOOL success) {
if (success) {
NSLog(@"AppDelegate: existing document opened from iCloud");
} else {
NSLog(@"AppDelegate: existing document failed to open from iCloud");
}
}];
} else {
// Nothing in iCloud: create a container for file and give it URL
NSLog(@"AppDelegate: ocument not found in iCloud.");
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:@"Documents"] URLByAppendingPathComponent:@"text.txt"];
MyTextDocument *doc = [[MyTextDocument alloc] initWithFileURL:ubiquitousPackage];
//_document = doc;
doc.delegate = self.viewController;
self.viewController.document = doc;
[doc saveToURL:[doc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
NSLog(@"AppDelegate: new document save to iCloud");
[doc openWithCompletionHandler:^(BOOL success) {
NSLog(@"AppDelegate: new document opened from iCloud");
}];
}];
}
}
- (void)queryDidFinishGathering:(NSNotification *)notification {
// (3) if Query is finished, this will send the result (i.e. either it found our text.dat or it didn't) to the next function
NSMetadataQuery *query = [notification object];
[query disableUpdates];
[query stopQuery];
[self loadData:query];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
_query = nil; // we're done with it
}
-(void)loadDocument {
// (2) iCloud query: Looks if there exists a file called text.txt in the cloud
NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
_query = query;
//SCOPE
[query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
//PREDICATE
NSPredicate *pred = [NSPredicate predicateWithFormat: @"%K == %@", NSMetadataItemFSNameKey, @"text.txt"];
[query setPredicate:pred];
//FINISHED?
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:query];
[query startQuery];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(@"AppDelegate: app did finish launching");
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil] autorelease];
} else {
self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPad" bundle:nil] autorelease];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
// (1) iCloud: init
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (ubiq) {
NSLog(@"AppDelegate: iCloud access!");
[self loadDocument];
} else {
NSLog(@"AppDelegate: No iCloud access (either you are using simulator or, if you are on your phone, you should check settings");
}
return YES;
}
Upvotes: 7