39

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: res

Ev.
  • 7,109
  • 14
  • 53
  • 87
patrick
  • 6,533
  • 7
  • 45
  • 66

10 Answers10

65

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.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • I'm using the project type `Command-line Tool` as well and I can't get a file to load from `NSBundle pathForResource`. Should I switch to `Cocoa Application` project type? I'm not sure I follow your suggestion of adding a new `Application` target; you mean add a new target in the existing Command-line tool project? – raffian Sep 23 '12 at 23:13
  • 1
    Yes, I meant to add a new target (of type Application) to your existing project. A normal command line tool is just an executable without a bundle. Any resources you add to your _Command-line Tool_ target is simply ignored (but Xcode doesn't warn you about that). – DarkDust Sep 24 '12 at 10:04
  • 15
    Command-line Tool targets can still link files using NSBundle pathForResource. You need tell the application to copy the file(s) into the products directory when it builds. Go into “Build Phases” tab, click “Add Build Phase”, and select “Add Copy Files”. Then simply drag the file(s) you need. – capikaw Aug 19 '13 at 21:12
  • great answer @DarkDust – Jagveer Singh Sep 10 '15 at 07:13
53

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.

  1. Select your project
  2. Select Target
  3. Select Build Phases tab
  4. Open the section labelled "Copy Bundle Resources"
  5. Drag and drop your .sqlite file into this section.

now your app will find this default sqlite database.

fawsha1
  • 780
  • 8
  • 13
  • 2
    I've found that Xcode adds certain types of files to the Copy Bundle Resources phase automatically, and leaves others out. For example, .html files (along with .strings, .png, etc.) are added automatically, but .js files are not. – dave Aug 06 '14 at 17:21
  • Add to the list that xcode does not automatically are .epub files – oky_sabeni Jun 19 '15 at 21:27
  • Xcode also does not include shell scripts in resources automatically. – sparkonhdfs Aug 09 '16 at 02:26
  • This works if I build my project using Xcode, but not using `swift build`. Any solution? – Jay Wang Feb 08 '18 at 22:13
  • @JayWong4 What happens using the build command? Are you getting an error message? – fawsha1 Feb 09 '18 at 02:22
22

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.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • thanks for reply, but files seem to be added to the target -> http://grab.by/6TG4 – patrick Oct 16 '10 at 16:44
  • @Patrick: Your target is called MetwitApi... does that mean that you use that bundle in some other application ? If so, then `mainBundle` would be wrong... instead, try `bundleForClass:[SomeClassFromApi class]`. – DarkDust Oct 16 '10 at 17:09
  • it's the same :( I you want I can send you the xcode project. – patrick Oct 16 '10 at 17:13
  • 1
    I normally don't do that, but OK. You can find my e-mail address at the bottom of my homepage. – DarkDust Oct 16 '10 at 17:20
  • 11
    @Patrick: A quick word on etiquette. People volunteer their time on sites and mailing lists to help the community as much as individuals. It doesn't help any future visitors to the site who find your question because they had the same problem when you post publicly then take things offline. It's also considered bad form to "latch on" to an individual with the burden of single-handedly helping you through your problem. Let the community help by keeping the question and answer in the community. That way you'll earn a good reputation and help the helpers do the same. – Joshua Nozzi Oct 16 '10 at 17:44
  • +1 for this one - instead of creating a new target application, I prefer adding existing file to the main application bundle. – Marcel Falliere Dec 06 '10 at 10:15
  • Just this line of your answer helped me "Is the file really included in the target?" Thank you! – Hamed Rajabi Varamini May 06 '12 at 13:37
5

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!

Dmitry Isaev
  • 3,888
  • 2
  • 37
  • 49
  • There is a build setting called `Combine high resolution artwork` / `COMBINE_HIDPI_IMAGES` to disable this. – Klaas Jul 09 '15 at 10:11
2

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")
Tony
  • 1,551
  • 20
  • 21
2

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!

edwardmp
  • 6,339
  • 5
  • 50
  • 77
  • This solved my problem after upgrading to Xcode 8.1. *** Warning: There is no command line tools for Xcode 8.1 when installed under OS X 10.1.66. – Ed of the Mountain Oct 31 '16 at 18:27
  • it works for me too. but I'm wondering if 1) is this clean? I've already a Copy File Phase. 2) wouldn't be cleaner to create another bundle (Resource.bundle), put there all the resources and link the CLP with the resource.bundle? – Kasper Oct 18 '18 at 16:01
1

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.

0

Filename is case sensitive on iPad. You need use small letters.

János
  • 32,867
  • 38
  • 193
  • 353
  • Well, consistent casing. Not necessarily 'small' but yep. That was the problem for me. :) – Ev. Mar 10 '15 at 04:18
0

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.

Robert Schmid
  • 436
  • 4
  • 14
-1

Make sure you spell your resource's file name properly. I just learned that the hard way. :)

gonzobrains
  • 7,856
  • 14
  • 81
  • 132