If I send the message
[[NSFileManager defaultManager] setUbiquitous:NO
itemAtURL:url
destinationURL:iCloudURL
error:&err]
to remove an item from iCloud, it doesn't actually delete the file on the Ubiquitous Container. Is this the expected behaviour?
The method returns NO and the error object contains
Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be
completed. (Cocoa error 512.)"
UserInfo=0x20870970
{NSURL=file://localhost/var/mobile/Applications/168EE8CD-4CDF-49BE-AD88-1DC7DD9CF25F/Documents/test.txt,
NSUnderlyingError=0x20863a00 "The operation couldn’t be completed.
(LibrarianErrorDomain error 2 - Cannot disable syncing on a unsynced
item.)"}
The error is pretty clear. You're trying to delete an item from iCloud that's not in iCloud. When you want to delete an item from iCloud using setUbiquitous:..., the item URL (itemAtURL:) should be the iCloud URL. The destination URL can be something local (but is ignored if ubiquitous is set to NO).
When specifying the "setubiquitous" parameter to "no", your destinationURL needs to be the local url, not the iCloud one. You have your URLs switched
To delete an item on iCloud, you can try this code:
NSError *err;
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateWritingItemAtURL:_url
options:NSFileCoordinatorWritingForDeleting
error:&err
byAccessor:^(NSURL* writingURL) {
NSFileManager* fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:writingURL error:nil];
}];
[fileCoordinator autorelease];
Good luck!
Related
Here I want to achieve a function which can copy a res file from main bundle (which is added manually from Mac Finder to Xcode project ) (Fig 1) to Document Folder.
Click here to see the Xcode project structure
And to achieve that goal, I use NSFileManager. Here is the function code:
- (void)addCamConfig {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *destPath = [documentsDirectory stringByAppendingPathComponent:CAM_CONFIG];
if (![fileManager fileExistsAtPath:destPath]) {
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"cam" ofType:#"yaml"];
BOOL ret = [fileManager copyItemAtPath:sourcePath toPath:destPath error:&error];
if (error) {
NSLog(#"cam_ret:%d\nsourcePath:%#\ndestPath:%#\nerror:%#",ret,sourcePath,destPath,error.description);
}
}
}
In that case, sourcePath and destPath are both ensured not to be nil.
But strange thing happened in the first time, "copyItemAtPath:sourcePath toPath:destPath error:&error" return "NO" and error log showed below:
cam_ret:0
sourcePath:/private/var/containers/Bundle/Application/3DF49723-E11D-4D67-AD0F-39C2B82B80A4/NitroDemo.app/cam.yaml
destPath:/var/mobile/Containers/Data/Application/181F8B72-402B-4D0C-91D5-0D9759BC607E/Documents/nitro/cam.yaml
error:Error Domain=NSCocoaErrorDomain Code=4 "The file “cam.yaml” doesn’t exist." UserInfo={NSSourceFilePathErrorKey=/private/var/containers/Bundle/Application/3DF49723-E11D-4D67-AD0F-39C2B82B80A4/NitroDemo.app/cam.yaml, NSUserStringVariant=(
), NSDestinationFilePath=/var/mobile/Containers/Data/Application/181F8B72-402B-4D0C-91D5-0D9759BC607E/Documents/nitro/cam.yaml, NSFilePath=/private/var/containers/Bundle/Application/3DF49723-E11D-4D67-AD0F-39C2B82B80A4/NitroDemo.app/cam.yaml, NSUnderlyingError=0x2826476f0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Surprisingly, when I run project second time, the error disappeared, "copyItemAtPath:sourcePath toPath:destPath error:&error" return "YES".
And if I remove this app from my iPhone, then rebuild the project , reinstall and run the app first time, the same error message appears again. And as I expected, when I run the project second time, the error disappeared.
So I wonder what exactly happened in the first time and second time?
====================
UPDATE: I solved this problem by creating an intermediate folder nitro.
The key point here is that, as you may not noticed in the log, the dest path XXX/Documents/nitro/cam.yaml contains a not existed intermediate folder nitro. So in the first time when I call copyItemAtPath:sourcePath toPath:destPath error:&error, it fails and may create that folder (just for my guess). As a result, when I run second time, the copyItemAtPath:sourcePath toPath:destPath error:&error returns YES.
Ok, based on the update you could solve it then by inserting something like below.
[NSFileManager.defaultManager createDirectoryAtPath:newDir
withIntermediateDirectories:YES
attributes:nil
error:NULL];
My OSX application is intended to monitor a folder on the computer which the user has selected. Very simply, I have a function which scans the directory:
- (NSError*)scan:(NSString*)dir {
NSError *err = nil;
NSArray *filenames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:&err];
for(NSString* fn in filenames) {
NSString *fp = [dir stringByAppendingPathComponent:fn];
BOOL isDir;
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:fp isDirectory:&isDir];
if(exists && isDir) {
[self scan:fp];
}
else {
[self handleFile:fp];
}
}
NSLog(#"Scanning %#: %#",dir,err);
return err;
}
When I first start the application, I present a UI to select the folder and then immediately scan it. The operation works great (no errors).
When I restart the application, I attempt to scan the directory again, but this time the NSLog spits out an error:
Scanning /Users/zane/Dropbox/Gifs: Error Domain=NSCocoaErrorDomain Code=257 "The file “Gifs” couldn’t be opened because you don’t have permission to view it." UserInfo=0x608000476d40 {NSFilePath=/Users/zane/Dropbox/Gifs, NSUserStringVariant=(
Folder
), NSUnderlyingError=0x60800005d3d0 "The operation couldn’t be completed. (OSStatus error -5000.)"}
Note that the path has not changed.
I suspect that the problem has to do with .entitlements. Here's what I've got:
If you are going to use the same file or folder the user already selected, then you need to save the path as a security-scoped bookmark when the user selects that path. Read its bookmark data when the user restarts the application in order to use the saved path. There's a description of security-scoped bookmark at the middle of this page. Use the URLByResolvingBookmarkData method of NSURL to return a security-scoped bookmark. Use the bookmarkDataWithOptions method or equivalent of NSURL to resume the security-scoped bookmark.
I get a weird issue while saving a file with writeToFile:options:error: In the first case I get the following issue:
writeToFile failed with error Error Domain=NSCocoaErrorDomain Code=4 "The file “preferences.plist” doesn’t exist." UserInfo=0xa12c30 {NSFilePath=file:/Users/patrick/Desktop/Untitled.fef/preferences.plist, NSUnderlyingError=0xa0d130 "The operation couldn’t be completed. No such file or directory"}
But the file actually exist in that location. The file is stored in the app document file package.
CODE: (Subclass of NSDocument)
NSString *prefFile = [[[self fileURL] absoluteString] stringByAppendingPathComponent:#"preferences.plist"];
NSError *error;
BOOL succes = [[NSKeyedArchiver archivedDataWithRootObject:documentPreferences] writeToFile:prefFile options:0 error:&error];
if (!succes) {
NSLog(#"writeToFile failed with error %#", error);
}
Make sure when using any of the ...toFilemethods of various classes that you use a real path and not by mistake a file URL. You can tell these apart by looking at the path. If the path starts with file://it can't be used. If it starts with a slash / it is a regular file path. Still you might use NSFileManager to check if the file exists.
As in your code instead of calling absoluteString on self.fileURL call path.
I'm trying to copy a file to iCloud using the follow code:
NSError *error;
//My Image Source file
NSURL *sourceURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"_219" ofType:#"jpg"]isDirectory:NO];
NSLog(#"source: %#", sourceURL);
NSFileManager *fileManager = [NSFileManager defaultManager];
//Discovering iCloud URL
NSURL *iCloudDocumentsURL = [[fileManager URLForUbiquityContainerIdentifier:nil] URLByAppendingPathComponent:#"Documents"];
NSLog(#"iCloudDocumentsURL: %#", iCloudDocumentsURL);
//Setting destination URL
NSURL *destinationURL = [iCloudDocumentsURL URLByAppendingPathComponent:#"image.jpg"];
NSLog(#"destination: %#", destinationURL);
//Copy file to iCloud
BOOL success = [fileManager setUbiquitous:YES itemAtURL:sourceURL destinationURL:destinationURL error:&error];
if (!success) {
#throw [NSException exceptionWithName:[error localizedDescription] reason:[error localizedFailureReason] userInfo:nil];
}
When I run this code I have the following result:
2012-12-31 15:15:30.888 iCloudTest[10614:907] source: file://localhost/var/mobile/Applications/B2202406-BEB8-41B6-A3C4-2327EFB85E54/iCloudTest.app/_219.jpg
2012-12-31 15:15:31.108 iCloudTest[10614:907] iCloudDocumentsURL: file://localhost/private/var/mobile/Library/Mobile%20Documents/xxxxxxxx~com~gazapps~iCloudTest/Documents/
2012-12-31 15:15:31.110 iCloudTest[10614:907] destination: file://localhost/private/var/mobile/Library/Mobile%20Documents/XXXXXXXX~com~gazapps~iCloudTest/Documents/image.jpg
2012-12-31 15:15:31.122 iCloudTest[10614:907] *** Terminating app due to uncaught exception 'The operation couldn’t be completed. (Cocoa error 513.)', reason: '(null)'
*** First throw call stack:
(0x38c312a3 0x32f1897f 0xbb617 0x3a31058d 0x3a350d71 0x3a34cae5 0x3a38e1c9 0xad241 0x3a351ad1 0x3a35165b 0x3a349843 0x3a2f1c39 0x3a2f16cd 0x3a2f111b 0x371295a3 0x371291d3 0x38c06173 0x38c06117 0x38c04f99 0x38b77ebd 0x38b77d49 0x3a34847d 0x3a3452f9 0xacff9 0x3627cb20)
libc++abi.dylib: terminate called throwing an exception
Looking at documentation, Cocoa error 513 means:
NSFileWriteNoPermissionError = 513,
So basically I'm without access to write stuff on iCloud... Looking at https://developer.icloud.com, everything seems to be ok (the documents folder is there).
What I'm doing wrong ?
iCloud has been working intermittently since December 30/31, even though everything may look good on developer.icloud.com. There's a discussion going on at the developer forums here:
https://devforums.apple.com/thread/176739?tstart=0
It's hard to diagnose iCloud issues at this point since it may just be problems on Apple's iCloud server. Some people have noted (on the discussion thread) that iCloud seems to be working better today than prior days so it may be worth testing your app again now.
I have an iPhone-iCloud app. Now one document has the state UIDocumentStateSavingError and UIDocumentStateClosed. I can see the file on developers.icloud.com with the status "file upload is pending". But i don't know what to do now
When i try to delete the file with the code:
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForDeleting error:nil byAccessor:^(NSURL* writingURL) {
NSFileManager* fileManager = [[NSFileManager alloc] init];
[fileManager removeItemAtURL:writingURL error:nil];
}];
the file is still there. I tried to delete the app on all devices but nothing changed. How can I delete this file or resolve the problem?
It's long ago but still unanswered, so if your problem persists:
For me it works to prepend the [fileManager removeItemAtURL:...] with a [fileManager setUbiquitous:NO...] on the file and then let the fileManager delete the local copy.
Take care to use NSError and boolean result handling of the fileManager actions to be sure it really works. So if you get back an NSError you could see the reason why it failed. That's always good practice.
I stumbled into your question because I get the message "File upload is Pending" after such a deleted file is re-created even if it's some hours between deletion and creation.