Unknown error creating file in objective c - objective-c

I'm creating a mac app that needs to create a file with the contents of another file, i'm creating it as follows:
NSString *p = #"/AfilethatEXISTS.plist";
NSString *user1 = #"~/Library/MyApp/myFile";
NSString *pT1 = [user1 stringByExpandingTildeInPath];
[[NSFileManager alloc] createFileAtPath:[NSURL URLWithString:pT1] contents:[NSData dataWithContentsOfFile:p] attributes:nil];
However returning no error, its not creating the file?

There are several things wrong with this code, but not enough context to tell you what is going wrong.
First, there should never be a file in / directly. That directory should be sacrosanct and many users will not be able to write to that directory without admin access.
Secondly, paths should be managed via the path manipulation APIs on NSString and NSURL.
Next, pT1 isn't really an URL and that is URLWithString: may be returning nil. Use fileURLWithPath: instead.
Finally, there isn't any error checking in that code and, thus, there is no way to tell how you might have discovered no error. What have you checked?

First off, you're creating the file manager instance incorrectly. To create a new instance, you need to both allocate and initialize it.
You're trying to pass an NSURL object, which won't be created correctly since the string you're using to create it with isn't a URL. But that doesn't matter anyway, because even if the NSURL was created, -createFileAtPath:contents:attributes: expects an NSString - just pass pT1 directly.
Better still, since you're basically just copying p to pT1, use the NSFileManager method for doing that. Not only is it conceptually a better fit, it also gives you a chance to examine a returned NSError object to see what (if anything) went wrong.
NSError *error;
NSFileManager *fm = [[[NSFileManager alloc] init] autorelease];
if (![fm copyFileAtPath:p toPath:pT1 error:&error]) {
// If copyFileAtPath:toPath:error: returned FALSE, an error occurred, and
// error will point to an NSError instance with more information
}

Related

using instance method instead of init

I just wroted this line:
BOOL directoryResult = [[NSFileManager alloc]
createDirectoryAtURL:[[NSURL alloc]
initFileURLWithPath:[self.documentsPath
stringByAppendingFormat:#"/level%d", levelCount] isDirectory:YES]
withIntermediateDirectories:NO attributes:nil error:nil];
NSLog(#"BOOL: %d", directoryResult);
and I have two questions: how it is possible that this method is working properly? After [NSFileManager alloc] I'm not using init.
Why compiler does not complaining? Is init inside createDirectoryAtURL? Is it good way of programming?
And secondly in URL parameter of createDirectoryAtURL I'm creating NSURL just in place
[[NSURL alloc] initFileURLWithPath:[self.documentsPath stringByAppendingFormat:#"/level%d", levelCount] isDirectory:YES]
same question as above: Is it good way of programming or should I create such object before that line and just put object here?
[NSFileManager defaultManager] returns singleton instance of the file manager, use it to perform the tasks. It's quite common practice in Cococa. I'm not sure why does your code work properly, I can only guess that this particular method doesn't use any internal variables, so it's valid to call it even without init (although you should never do that).
As for the NSURL construction, the answer depends on compiling options. Do you use ARC? If the answer is 'yes', your code is valid, else it lead to the memory leak. In generat it's better either to create an object and call autorelease (non-ARC apps) explicitly, or use class methods like [NSURL fileURLWithPath:path].
Also, don't treat it as offense, but I believe you're asking this questions in the wrong place. Basic memory management questions should be asked to a good book, one like "Cocoa programming for Mac OS X" by Aaron Hillegass.
It's not guaranteed that object created without initialization will work properly. So you should init the object. Documentation example:
BOOL isDir=NO;
NSArray *subpaths;
NSString *fontPath = #"/System/Library/Fonts";
NSFileManager *fileManager = [[NSFileManager alloc] init];
if ([fileManager fileExistsAtPath:fontPath isDirectory:&isDir] && isDir)
subpaths = [fileManager subpathsAtPath:fontPath];
[fileManager release];
Also NSFileManager has a shared manager (already created and intialized object)
NSFileManager* fileManager = [NSFileManager defaultManager];
But there is a warning in documentation:
This method always returns the same file manager object. If you plan to use a delegate with the file manager to receive notifications about the completion of file-based operations, you should create a new instance of NSFileManager (using the init method) rather than using the shared object.

Drag Files come across Sandbox(__CFPasteboardIssueSandboxExtensionForPath)

I processed drag operation from browser view to custom view.It work well in snow lepoard,but not in Mountain Lion with sandbox.
in browser view:
NSMutableArray* urls = [[[NSMutableArray alloc] init] autorelease];
..............put some NSUrl to urls array....................
[pasteboard writeObjects:[NSArray arrayWithArray:urls]];
in my receive custom view:
NSArray* pasteboardItems = [pasteboard readObjectsForClasses:[NSArray arrayWithObject:[NSString class]] options:nil];
NSArray* pasteboardItems2 = [pasteboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:nil];
NSArray* pasteboardItems3 = [pasteboard readObjectsForClasses:[NSArray arrayWithObject:[NSImage class]] options:nil];
NSLog(#"%#",pasteboardItems);
NSLog(#"%#",pasteboardItems2);
NSLog(#"%#",pasteboardItems3);
my log is:
2012-08-09 18:33:43.886 iCollage[6885:303] __CFPasteboardIssueSandboxExtensionForPath: error for [/Users/xxxx/Library/Containers/xxxxxxxxxxxx/Data/Downloads/1343902069.jpg]
2012-08-09 18:33:44.546 iCollage[6885:303] ( "file://localhost/Users/xxx/Library/Containers/xxxxxxxx/Data/Downloads/1343902069.jpg")
2012-08-09 18:33:44.547 iCollage[6885:303] ( "file://localhost/Users/xxxxx/Library/Containers/xxxxxx/Data/Downloads/1343902069.jpg")
2012-08-09 18:33:44.547 iCollage[6885:303] ()
my question is:
1.how to fix this error __CFPasteboardIssueSandboxExtensionForPath;I refer the docs and found nothing about that.I am ensuer that i have the permission to access the file!google says, may be "startAccessingSecurityScopedResource" will help me, then i try and failed
2.why pasteboardItems2 have value?i write to pasteboard only url but not string.It disgusted me that I can get the url both from NSString type and NSUrl type! (I try drag a file from iFinder, the url will only exist in pasteboardItems but not pasteboardItems2).Anybody know why? I think the first problem will auto fixed when some one help me fix this problem.
I believe Apple answer question 1:
Important: Although you can support dragging file paths, in general,
you should avoid doing so unless you are certain that the destination
app will never be run in an app sandbox. If you use an NSString, OS X
has no way to know whether that string should be interpreted as a
path; thus, OS X does not expand the destination app’s sandbox to
allow access to the file or directory at that location. Instead, use
an NSURL, a bookmark, or a filename pasteboard type.
WRT to question 2, it looks like you have pasted URLs so reading NSURL objects would seem to be correct. However I think you should implement the dragging using the following code (also from the link above):
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
int numberOfFiles = [files count];
// Perform operation using the list of files
}
return YES;
}
You need to generate security-scoped URL bookmark data on the sender side, and turn that data back into a URL on the receiver side. There's some other stuff you have to do after that when you want to actually access the URL; the documentation elaborates.
The receiving application, when running in a sandbox, will not be able to handle bare paths. This is a core part of being sandboxed; you are not allowed to use bare paths or their corresponding URLs to access files that aren't in your sandbox container and haven't been explicitly handed to you by the user.
Your pasteboardItems read object of NSString type, but you dragged a file(with jpg extension), you should register for NSString type in your init method:
[self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeString]];
You need to have Document Types defined in your application so that the sandboxing mechanism knows your application should be opening files with those extensions. You can do this by clicking the project on the left in Xcode, and in the Info tab, under Document Types add a new document type for each extension.
You just need to fill in the name and extensions field.
Also if you want to persist your permission to access the files dragged onto your application, you can use this class to wrap up all that logic. https://github.com/leighmcculloch/AppSandboxFileAccess

Xcode keeps telling me my usage of NSDirectoryEnumerator is wrong.

I am trying to instantiate an NSDirectoryEnumerator from a NSFileManager like this
NSDirectoryEnumerator *enum = [fm enumeratorAtURL:*url includingPropertiesForKeys:nil options:nil errorHandler:nil];
and Xcode keeps coming with an error message that even after reading the complete FileManager and DirectoryManager Documentation doesn't make any sense to me:
Expected identifier or '('
Do I have to import anything else than Core Foundation to use NSDirectoryEnumerator or is there some special trick to the usage syntax that I am missing?
// edit:
url is of course a valid NSURL. Just in case this might come up.
In C and, by extension, Objective-C, enum is a keyword. Change the variable name.
Also, you need to remove the asterisk, unless it's a pointer to NSURL * (i.e. NSURL **) as commented by #WTP:
NSDirectoryEnumerator *enum = [fm enumeratorAtURL:*url includingPropertiesForKeys:nil options:0 errorHandler:nil];
^
Right here!
And the options parameters should be 0, not nil as noted by #omz.

How to handle the exceptions

NSString *stringURL=[[NSString alloc] init];
stringURL=[stringURL stringByAppendingFormat:kSearchBarURL,text.text];
NSString *url = [NSString stringWithString:stringURL];
NSData *data1 = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
NSString *responseids = [[NSString alloc] initWithData:data1 encoding:nil];
responseids = [responseids stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"\n\r\t"]];
SBJsonParser *parser=[SBJsonParser new];
NSData *data = [parser objectWithString:responseids error:nil];
NSMutableDictionary *searchURL = (NSMutableDictionary*)data;
I coded this i did not handle the exception for my code.
doing json and calling the service url and loading the data.
the application get crashes when my service is too low or no service found.
How to handle the exception for my code here..
Do I use #try #catch.
or
NSURLConnection for error handling.
Please help me out .
Thanks in advance.
Whenever an API makes use of NSError, you should use this rather than wrapping things up in a try…catch block as NSError is designed exactly for this. I usually reserve #try for things where I am really not able to anticipate what might go wrong. If NSError is in the mix, then you know that there is a potential for a problem that you should be handling gracefully.
More generally, your code has some strange stuff in it. You alloc init an empty NSString and then create a new string by appending a format. Not sure why you don't just use [NSString stringWithFormat]. Once you have the string, you can create the URL without the NSString *url bit.
You're also using a synchronous call to what I assume is a remote server. This has the potential to bog down your application if/when the server is not available. You're also not telling NSString what kind of encoding you expect your string to be in when it reads it from NSData. A better method depending on your server side would be to use NSString's stringWithContentsOfURL:usedEncoding:error: method. I would recommend that you use the various NSURLConnection callbacks. Have a look at the URL Loading System Programming Guide on Using NSURLConnection The NSURLConnection delegate methods are the ones you want to implement to provide this asynchronous processing.
For your trimming, you might be interested in the +whitespaceAndNewlineCharacterSet method on NSCharacterSet.
Finally, for your JSON parsing, you might be interested in the category that the SBJSON code adds to NSString, particularly -JSONValue which will give you the dictionary or array representation (as appropriate) of the NSString when parsed as JSON by SBJSON.
HTH

Converting File Path From NSString To NSURL

I'm working through Cocoa smoothly, but this problem seems so basic it cancels out all the cool stuff I learned. :/
I have a generated file path, and it needs to be in NSURL format. From research, this is the code I wrote:
NSLog(#"Old path = %#", pathToFile);
NSURL *xmlURL = [[[NSURL alloc] init] fileURLWithPath:pathToFile];
NSLog(#"New path = %#", [xmlURL absoluteString]);
And the output:
2010-01-27 15:39:22.105 MusicLibraryStats[28574:a0f] Old path = file://localhost/Users/[username]/Music/iTunes/iTunes%20Music%20Library.xml
2010-01-27 15:39:22.105 MusicLibraryStats[28574:a0f] New path = (null)
First off, the alloc-init shouldn't even be necessary; other people seem to get away with it. In this case, if I don't alloc-init, I get an 'unrecognized selector' error on that line. Of course, now I'm just getting plain old (null).
Where did I goof?
Thanks!
The [[NSURL alloc] init] is not just unnecessary, it's invalid. fileURLWithPath: is a class method, which means you can only call it on the class object (that is, NSURL itself). It does not produce a compile error because -(NSURL *)init returns an object of type id, and does not result in a runtime error because -(NSURL *)init actually returns nil, and messages sent to nil will just cascade another nil as their return value.
This code should work:
NSString* pathToFile = #"/this/is/a/path";
NSURL* url = [NSURL fileURLWithPath:pathToFile];
I found your problem.
-[NSOpenPanel URLs] returns an array of NSURL objects, which you treat as NSString objects. That's not right. You should use the following:
NSURL* url = [[oPanel URLs] objectAtIndex:0];
The debugger could've show you that if you looked at the pathToFile variable. Make sure to check it next time. :) Hovering a variable with your mouse should get you its type.
However, remember that there are situations where you will legitimately encounter another type than the one you expected. For instance, the private NSPathStore2 class is part of the NSString cluster, and you can do everything NSString supports on NSPathStore2 objects. (If this happens and you're not too sure, check the documentation to see if the type you expect is a cluster type. That's how they're called in the documentation.)