I know .xib files are really .xml files (as evidenced primarily by the fact that I can rename their extension and open them in text edit and dashcode), so theoretically, it would be possible to open a xib as xml and parse it in an application. I took a look in the Build Settings for my sample app, and found that xib's aren't compiled, rather they are Copy bundle Resources. Sounds good, right? But the files are giving me (null) strings when I try and get their text with these methods:
NSString *string = [[NSBundle mainBundle]pathForResource:#"Empty" ofType:#"xib"];
NSString *xmlString = [[NSString stringWithContentsOfFile:string encoding:NSUTF8StringEncoding error:nil] retain];
NSLog(#"%#", xmlString);
[textView setText:xmlString];
It NSLog's (null) both for xmlString and for string. So I thought of trying it with another Copy Bundle Resource, so I changed string to this:
NSString *string = [[NSBundle mainBundle]pathForResource:#"InfoPlist" ofType:#"strings"];
and it logged a perfect file path! However, xmlString still logged (null).
Then, I tried getting an error code, and I got this:
The operation couldn’t be completed. (Cocoa error 258.)
It makes me think there is some extra compiling going on behind the scenes with .xib files (I read somewhere that they are turned into nibs by the compiler) that is making them unreadable or unreachable. But there are apps out that I know of (Interface being a prime example) that can read and write .xib files.
So, can anyone help me get the xml of a .xib file?
Actually xib files are compiled into nib files. Use Show Package Contents on the compiled .app and you will see that there are no xib files but nib files instead.
Edit It looks like the nib file format is a proprietary format. But I am not sure.
Form Apple documentation:
The original format uses files with extension .nib. This a proprietary, binary format for the representation of Interface Builder user interface objects and connections.
Edit 2 It looks like there is some option to prevent Xcode from compiling the xib files into nib files. But I am still not sure about how to do that, and what is the actual result.
Edit 3 I tried that on Xcode. When I turned Flatten Complied Xib files to No, I still got nib files in the binary but they are not compressed this time. Inside these nib files there is a file designtime.nib that has an xml format.
Related
My question is about the application bundle in a project. I was reading about that and can understand some basic things (I'm not a native english speaker). I can understand that the resources folder is used to hold the files that will be used in the project, e.g. media files (images, audio, video, etc.) and should be in the application bundle to be identified.
So, what is the point if I want to use images and another resources in my project? In my other related question, I can't use them by referencing with NSImage imageNamed:.
I have used the following with no success loading my files:
NSBundle methods
imageNamed:#"string" with/without file extension
the images are in resources folder
I'm learning Cocoa and Objective-C, and of course this is different to C++ or Java when I want to create an ImageIcon or a QImage.
I may not have completely understood the issue, so correct me if I am wrong. I believe the problem has to do with your image's target membership or how you're retrieving the image in your code.
Adding an image to your project target will appropriately copy the resource at compile time. To add the image to your target, select it in the file navigator and then reveal the Utilities Panel. On the Utilities Panel, select the File Inspector Tab. Look for the Target Membership section and ensure that the image is selected for the desired targets:
Do you mean that you can't use the NSImage imageNamed: method to retrieve resources? If so, you can retrieve the resource like this (from the main resource bundle):
NSString *imageName = [[NSBundle mainBundle] pathForResource:#"image1" ofType:#"png"];
NSImage *imageObj = [[NSImage alloc] initWithContentsOfFile:imageName];
It also looks like you already have a good answer to your other related question.
I've got a PGN file called a00.PGN in my project, which I'd like to parse to 'preload' into Core Data. Right now I'm just trying to output the file as a string with NSLog using
NSError *err = nil;
NSString *datapath = [[NSBundle mainBundle] pathForResource:#"a00" ofType:#"PGN"];
NSString *content = [NSString stringWithContentsOfFile:datapath encoding:NSASCIIStringEncoding error:&err];
NSLog(#"%#", err);
And I'm getting an error: Error Domain=NSCocoaErrorDomain Code=258 "The file name is invalid."
When I NSLog the string content it is NULL.
I have tried changing the extension to .txt but the same error is received, and have also used NSUTF8StringEncoding. What is the best way to read in this file for parsing in objective-c?
Edit 1:
To include the file in my project I dragged it from finder. I then went to my projects target and added it to the Copy Files section with Products Directory as the destination. The Subpath is empty.
Edit 2:
I've uploaded the current state of this simple project to a repo here: https://github.com/justinjdickow/PGN-Parse-into-Core-Data/
According to Technical Q&A QA1436: What is the "main bundle" of a command-line foundation tool? — actually, that document is (partially) wrong.
In a command-line tool executable, the main bundle's path would be the directory that contains the executable itself. For example, in a sample command-line tool project I made here, the following was logged to console:
mainBundle == NSBundle <~/Library/Developer/Xcode/DerivedData/mainBundle-bqmiidcdlnwumjgcnblqgtelpecl/Build/Products/Debug> (loaded),
bundlePath == ~/Library/Developer/Xcode/DerivedData/mainBundle-bqmiidcdlnwumjgcnblqgtelpecl/Build/Products/Debug
In other words, the main bundle will be your built-products directory. For NSBundle's pathForResource:ofType: to be able to find the "A00.PGN" file at runtime, that file will need to be in your built-products directory along with your executable. For example, in my case, I would need the file to be located at ~/Library/Developer/Xcode/DerivedData/mainBundle-bqmiidcdlnwumjgcnblqgtelpecl/Build/Products/Debug/A00.PGN
The easiest way to achieve that is to add a Copy Files build phase to your command line tool target. Specify the Destination as the Products Directory and include the A00.PGN file in the list of files to be copied.
Also, as others have already mentioned, NSBundle's search method is case-sensitive even if the underlying HFS+ file system on OS X is merely case-preserving. So, make sure you specify the correct filename and filename extension in your code.
Note that pathForResource:ofType: has different case-sensitivity depending whether it is iPhone simulator or iPad simulator or the device.
Make sure you are using upper/lower case consistently.
Our graphic designer is sending us .PNGs named appropiately "hide_00~iphone.png", "hide_00#2X~iphone.png" etc
He is exporting the images from after effects. I add them to the project and try to load them into an array on init. An exception is thrown each time for all of his files. Now, if I go in AND RENAME the files in the finder to exactly the same name, everything compiles fine. I have no idea what's going on here. Xcode cannot find them in the file system until I rename them. But the name is EXACTLY the same as what he sent me. I checked for white space around his file naming but everything looks fine.
Does anybody know if After Effects puts weird header info in the images? Or does this sound familiar at all to anyone. There are a whole bunch of images we are working with and I would hate to have to rename them by hand.
So I just used imageNamed and the image loaded just fine. So obviously your routine to load the image by path/name is flawed. You can post that and it can be evaluated - but this has nothing to do with 'After Effects'.
EDIT: For the record, my system is Lion Xcode 4.4.1 and my project set for iOS 5.1. I took your file from dropbox, and verified that in my project I CAN load the image as you are trying to do:
for (int i = 6; i < 7; i++) {
NSString *path = [NSString stringWithFormat:#"hide_step_seq_%02d", i];
UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:path ofType:#"png"]];
NSLog(#"PATH %# image=%#", path, image);
}
2012-09-13 07:15:23.241 Searcher[58114:f803] PATH hide_step_seq_06 image=<UIImage: 0x6a4cb30>
So, where to go from here? I've tried to help several people here who get burned by the #2x or ~iphone suffixes. For some reason a few people cannot ever seem to get this to work - all I can think of is there is some flag deep in the system that gets toggled and there is no way to untoggle it.
My suggestion is to try using the actual complete file name - try appending ~iphone and see if that works.
You can also in Terminal do a 'ls *.png | od -c' before changing the name and afterwards, to verify that absolutely the characters are the same.
The last thought I have on this is that files have many attributes: creation time, last access, last modiied, extended attributes, permissions, etc. It is possible (while unlikely) that for some reason one of these values blocks the system from attempting to use the ~iphone suffix.
I really wish I could help you further. If you want to put a simple little project together that does nothing more than tries to open a few images and it fails, zip the whole project up, put on dropbox, I'd be more than willing to run it on my system to try and duplicate the problem. You can also do as I did in the code above and verify that path looks good and the image is nil.
I have created a new folder in my project in which I have copied an image (called "io.jpg").
I also have checked on build phases -> copy bundle resources and the file is there.
So I am trying to get the path of this image:
NSBundle* bundle=[NSBundle mainBundle];
NSString* path=[bundle pathForResource: #"io" ofType: #"jpg"];
NSLog(#"%#",path);
But it prints (null), I also have tried this way:
NSBundle* bundle=[NSBundle mainBundle];
NSString* path=[bundle pathForImageResource: #"io"];
NSLog(#"%#",path);
But it still prints (null).
What's the problem?
Go to : Target -> "Build Phases" -> "copy bundle Resources" Then add that particular file here.
clean the project and RUN. It works. :)
My guess, given that you said you created a new folder in your Xcode project is that you have created a blue folder reference and your image resource is in a sub directory of your bundle.
I'd be willing to bet it's not a bug with NSBundle, given how old and crutial the class is to the Foundation framework.
Try and access your resource using the more specific instance method
- (NSString *)pathForResource:(NSString *)name ofType:(NSString *)extension inDirectory:(NSString *)subpath
where subpath is the name of the folder reference I am guessing you created.
You'll get a nil path if the resource you're requesting doesn't exist in the output (or doesn't exist where it should). That's really the only reason I've seen.
Forget about proving it should exist, and just check the output to make sure it does.
(Remember also that filenames are case sensitive.)
To clarify, you should be looking in the output bundle in ~/Library/Developer/Xcode/DerviedData/Project-{GUID}/Build/Products. Your image will be missing.
I had a problem like this a few weeks ago. And it turned out I just hadn't ticked a box. Here is the answer I got when I asked.
"Select the file on in the Xcode Project Navigator (to the left) and make sure that your target is checked under "Target Membership" in the File Inspector (to the right). -- Also double-check the spelling of the file names – Mundi"
All of this is kind of overkill if you're just trying to get an image. Let's say you have included bundleImage.PNG in your application bundle.. somewhere, somehow…
NSImage *image = [NSImage imageNamed:#"bundleImage"];
will, for sure.. find it… If it's there… Can't get more simple, right?
If - in the off chance - it's a slightly more complicated situation, like the image is in a loadable bundle or framework - you can use code similar to the following (a class category on NSImage) which will also return the resource.
+ (id) imageInFrameworkWithFileName:(NSString *) fileName {
NSBundle *b = [NSBundle bundleForClass: [DummyClass class]];
return [self imageWithFileName: fileName inBundle: b];
}
To be honest, I don't really understand the concept of, or how such a "Dummy class" works.. but this is what it looks like
#interface DummyClass : NSObject
#end
#implementation DummyClass
#end
Try removing the image from your app.And then adding it again.And clean your build before running it.See if it helps.Otherwise please give a screenshot of your project navigator showing where is the image added.It must be in the top level of your Application.app.Is it somwhere inside any folder/sub-folder.
I'm creating a simple application with xcode and objc and I need to load an NSDictionary from a file, but I can't get the path to the file using NSBundle:
NSString *l = [[NSBundle mainBundle] pathForResource:#"LoginStatuses" ofType:#"plist"];
NSLog(#"%#", l);
When I run this code I get this:
2010-10-16 10:42:42.42 Sample[5226:a0f] (null)
And I don't know why.
I created a group called Resources and there I added the LogingStatuses.plist:
So here's the solution for this problem after I got the source:
I didn't really pay attention to the posted screenshot, but the target is of type "Command-line Tool"... and since those don't have a bundle [NSBundle mainBundle] of course returns nil. It's pretty misleading that Xcode doesn't complain that it can't execute the "Copy Bundle Resources" step, it just silently skips it.
Solution is simply to add a new target, of type "Application" so a bundle-based application is generated. Then check the Target Membership checkboxes for all sources and resources for this new target. The plist paths are correctly resolved then.
I was trying to get my iPhone app to use a default sqlite database and the darn app couldn't find it. Turned out that I had to make sure that the .sqlite file was in the bundle resource.
Select your project
Select Target
Select Build Phases tab
Open the section labelled "Copy Bundle Resources"
Drag and drop your .sqlite file into this section.
now your app will find this default sqlite database.
Is the file really included in the target (and will therefor be copied to the bundle) ? There two ways to find out/set that:
First way: right-click (or Cmd-click) on the file, select "Get Info". Then click on the "Targets" tab and make sure the file is checked for the desired target(s).
Second way: right-click (or Cmd-clock) in the project browser on the header of the file browser (it will likely read "Groups & Files"). Then select "Target Membership". Now you have checkboxes next to each file that can be member of a target (like .m files or resources). Again, make sure the checkbox next to your file is checked.
Since I have googled here, did not find the answer, but then discovered it by myself, I'll leave it here...
I had 2 files: tray.png and tray#2x.png for Retina. The files were added to "Copy Bundle Resources" automatically.
But:
[[NSBundle mainBundle] pathForResource:#"tray" ofType:#"png"];
did not return the file actually copied to the bundle! The reason was: IDE created one TIFF file tray.tiff (joint tray.png and tray#2x.png), so ... ofType:#"tiff"] helped!
My problem and solution are very similar to Dmitriy Isaev's ones. I have tried to get path for a xib file. Both calls (in Swift) pathForResource("myfile", ofType: "xib") and pathForResource("myfile.xib", ofType: nil) are failed.
The solution is to use extension "nib" instead:
pathForResource("myfile", ofType: "nib")
I encountered this issue today with a Command Line project.
Luckily, the solution is easy. Simply go to "Build Phases", click on "+" and add a new "Copy Files" phase. Choose "Resources" as Destination, and add any files you want to use.
Now you can still use [NSBundle mainBundle] and it should work!
In my case (executing XCTestCase) for some reason resources were stored in non-main Bundle. I fixed the problem by checking first which bundle test class belongs to:
[[NSBundle bundleForClass:[self class]] pathForResource:#"Config" ofType:#"plist"];
Hopefully this can help someone else as well.
Filename is case sensitive on iPad. You need use small letters.
There is a way to do this for a Command-Line app.
Instead of using "Copy Bundle Resources" use "Copy Files". For "Destination" select "Resources". This will copy the file to the app bundle and the Bundle.main can find it.
Make sure you spell your resource's file name properly. I just learned that the hard way. :)