NSBundle Help

Discussion in 'Mac Programming' started by larswik, Jul 7, 2011.

  1. larswik macrumors 68000

    Joined:
    Sep 8, 2006
    #1
    I am almost finished with my super cool Experience Point calculator for our RoleMaster RPG. (yep, I am a geek at heart!). I did a release build and the images files were not there. Chown33 explained to me that I need to us the NSBundle and I read the documentation but I did not understand it completely. I then scoured the web and everything tutorial wise is for Xcode 3 or iPhones.

    Here is how I access my images right now.
    Code:
    -(void)setRoundImages{
        NSImage *rOneOff = [[NSImage alloc] initWithContentsOfFile:@"/Volumes/Media_Projects/Programing/Objective_C/Xp Calc2/images/rOneOff2.png"];
        [roundOneLight setImage:rOneOff];
        [rOneOff release];
    
    I have all my images in an image folder within my project. If I understand NSBundle correctly I use it to gather my images and bring them into the program to use. Do I bring in just the image folder or each image by it's self?

    If anyone has any links to any tutorials that explain this better or sample files, I would be thankful. There are so many Methods in the NSBundle class and I am getting lost.

    This is the last step before I can do the final working build! Then I can share it!

    -Lars
     
  2. Kenndac macrumors 6502

    Kenndac

    Joined:
    Jun 28, 2003
    #2
    NSBundle is a class for managing bundles of files, like Applications and so on. [NSBundle mainBundle] represents the currently running application's bundle.

    You need to drag all of your images into the source list of your Xcode project if they're not already there.

    Once they're there, Xcode will copy the images into your application bundle on build.

    Once there, you can use an NSImage method to get them out - so the code:
    Code:
    -(void)setRoundImages{
        NSImage *rOneOff = [[NSImage alloc] initWithContentsOfFile:@"/Volumes/Media_Projects/Programing/Objective_C/Xp Calc2/images/rOneOff2.png"];
        [roundOneLight setImage:rOneOff];
        [rOneOff release];
    
    ... becomes ...

    Code:
    -(void)setRoundImages{
        NSImage *rOneOff = [NSImage imageNamed:@"rOneOff2.png"];
        [roundOneLight setImage:rOneOff];
    
    FWIW, [NSImage imageNamed:] is basically a shortcut for:

    Code:
        NSString *path = [[NSBundle mainBundle] pathForResource:@"rOneOff2.png" ofType:@""];
        NSImage *image = [[NSImage alloc] initWithPath:path];
        return [image autorelease];
    
     
  3. PatrickCocoa macrumors 6502a

    Joined:
    Dec 2, 2008
    #3
    Forget File Structures

    There's your problem right there. You are trying to manage your assets (images) using the operating system's file structure.

    Apple has been on a crusade for about a decade to have each application handle its own data and files. All interaction with the files will be through the application, not through the operating system. See iTunes and iPhoto for examples of this. It's even more stringent on iOS.

    In this case, you need to let Xcode handle your assets. How to do this? Get your asset files (using the operating system) and drag and drop them into Xcode in your Project Navigator panel. Xcode will ask if you want to copy them into its Xcode secret location. Say Yes.

    Now when you're coding in Xcode and you need an image, it shows up in your Project Navigator. That item in your Project Navigator points to the actual file (that Xcode copied to its secret location).

    Note that now there are two copies of these files - the original and the one that Xcode copied to its secret location. You can do whatever you want to the original (if you answered Yes to Xcode copying it) and it won't affect Xcode or your code.
     
  4. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #4
    Thanks guys. I was looking for the secret folder but could not find it. I did drag in a couple of images into that folder. Later I wanted to change it and tried to delete the items. It asked me if I wanted to remove the reference or delete it. I selected Delete. I made change in Photoshop and tried to drag it back into the project but it said it already existed/ I had to rename it and drag it in again. Is there a way to get to that folder to physically delete the items?

    -Lars
     
  5. wlh99 macrumors 6502

    Joined:
    Feb 7, 2008
    #5
    In Xcode right click on a file and select reveal in finder, and it will open the folder the file is in. You can delete the file there. If that doesn't work, the "secret location" is just your project folder, or possibly a subfolder of that. If you know the filename, you can always resort to a spotlight search.

    Back you your earlier questions about NSBundle.

    If you right click on any .app file, you can open the package contents. That is what is refered to as a Bundle. NSBundle gives you the location of inside that file. You can do this with any .app file, even the programs in your applications folder.

    There is a folder in that file, resources. That is where xcode will copy all of your images. To access them.

    1. Use NSBundle to get the mainbundle.

    2. Send the mainbundle the -resourcePath message to get the path to the resource folder in your .app

    3. Append to the returned NSString the filename of your image. IIRC you need to include the leading "/" like @"/image.png"

    4. Use that NSString with the initWithContentsOfFile: method

    I would suggest NSLogging after each step so you can see what is happening, and read the docs to NSBundle again.

    Edit:
    I just reread your last post. Is the image file you are editing with photoshop in you project folder(in finder not xcode)? If so, that might be your problem. Xcode can't copy the file there, because it is already there. Move the file out of your project folder. Then when you drag it into Xcode, it will copy back into your project folder.
     
  6. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #6
    There are NSString methods for working with pathnames. Do not do pathname dissection/assembly manually.

    And the whole "build the pathname" strategy is flawed. There are NSBundle methods for returning resources. See Resource Programming Guide under heading "Loading Image Resources".
     
  7. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #7
    Just an aside...

    This is precisely the kind of thing I was talking about in Lars' other recent thread.

    This kind of "build the pathname" strategy is usually a legacy of learning how to do something similar this way in a lower level language like C.

    And that takes some "unlearning" to avoid.

    When the tool you are most familiar with is a hammer, everything starts to look like a nail, even if you have other tools at your disposal.

    B
     
  8. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #8
    Hey, slightly different question but applies to my same project. I use this code
    Code:
     [buttonOne setKeyEquivalent:@"1"];
    to assign a key equivalent for my calculator program. I reassigned a few keys to fit what I needed for an Experience Points calculator.

    I can not seem to be able to find the key equivalent to the 'clear' button on the keypad, the located above the '7' button. Does anyone off hand know if it can be assigned and what it is?

    Thanks

    -Lars
     
  9. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #9
    Code:
        unichar clearKeyEquiv[] = { NSClearLineFunctionKey };
        [button setKeyEquivalent:[NSString stringWithCharacters:clearKeyEquiv length:1]];
    
    These NS...Key constants are documents in Function-Key Unicodes of the Constants section of the NSEvent class reference.
     
  10. Catfish_Man macrumors 68030

    Catfish_Man

    Joined:
    Sep 13, 2001
    Location:
    Portland, OR
    #10
    This is not actually quite true. It will search your bundle, yes, but it also searches a bunch of other places as well (system shared images, and the named images table for example), and sets the name of the image if not already set, and impacts some caching decisions. Check the docs for details.

    Your NSBundle code is also not quite right. Don't put ".png" in the resource name, put @"png" as your type instead of an empty string. OR, even better, use NSBundle's -URLForImageResource: method. It automatically adapts if you change image types, is more filesystem efficient (NSURL caches fs info and is the modern way to deal with paths), and is less characters.

    A shorter way to do this may be forthcoming. Ping me after Lion is released or check the docs.
     
  11. PatrickCocoa macrumors 6502a

    Joined:
    Dec 2, 2008
    #11
    Basic Operations

    Yes. This was one of the biggest hurdles for me in moving from procedural programming (Pascal, PL/I, BASIC, Fortran, APL, COBOL) to Objective-C. In those other languages, there is a small set of basic operations (add, subtract, print, save, GOTO, For/Next), maybe 40 or 50 in total. To write a program, you thought in those small steps and constructed solutions.

    In Cocoa / Objective-C, almost all of the solutions have already been constructed. There are probably 2,000 "basic operations" in Cocoa (those would be the various methods of the various classes). To write a program, you string together sets of these pre-constructed mini-solutions.
     
  12. Kenndac macrumors 6502

    Kenndac

    Joined:
    Jun 28, 2003
    #12
    That snippet is an (extremely simplified) example of what [NSImage imageNamed:] might do if you pass in "name.png". It *might* do what I did or it might split the extension out. Neither of us know what it actually does.

    Obviously, if you're using NSBundle directly, split them up if you know what resource type you're working with up front.
     

Share This Page