NSSavePanel

Discussion in 'Mac Programming' started by liptonlover, Jul 26, 2008.

  1. liptonlover macrumors 6502a

    Joined:
    Mar 13, 2008
    #1
    I'm trying to get a savePanel working, just.. because. So, I'm using NSSavePanel. I have a simple application, all it has is a so far useless textfield, and a save button. I have outlets that are definitely going to the window (in case I decide to do a sheet) and to the textfield. (for when this is "done") I also have an action coming from the save button. I KNOW my connections are good. Here's my class files:

    #import <Cocoa/Cocoa.h>

    @interface AppController : NSObject {
    NSSavePanel *savePanel;
    IBOutlet id savingPanel;
    IBOutlet id text;
    IBOutlet id myWindow;
    }
    - (IBAction)savePressed:(id)sender;
    @end


    #import "AppController.h"

    @implementation AppController
    - (IBAction)savePressed:(id)sender {
    [savePanel runModalForDirectory:mad:"" file:mad:""];
    }

    - (void)awakeFromNib {
    [savePanel setTitle:mad:"Save game"];
    [savePanel setPrompt:mad:"Save"];
    [savePanel setCanCreateDirectories:1];
    }
    @end



    I don't get any errors, it runs. But pressing save does NOTHING. Nothing changes. What's wrong?
     
  2. MrFusion macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #2
    It seems to me that you are not initializing an NSSavePanel.
    Use
    Code:
    + (NSSavePanel *)savePanel;
    
    There is also only one shared panel, if I am not mistaken.
    Your savePanel is not pointing to any object.
     
  3. liptonlover thread starter macrumors 6502a

    Joined:
    Mar 13, 2008
    #3
    I thought I was initializing it by declaring it...
    NSSavePanel *savePanel;
    This should both init it and point to the one I just created.
     
  4. Cromulent macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #4
    Nope. That is not how pointers work. All you have done is said savePanel points to a location in memory that contains an NSSavePanel. But you haven't actually got an NSSavePanel for it to point too nor have you actually told it where in memory it is pointing. Basically it is just a junk memory reference that could contain anything.

    Consider this:

    If you have a pointer to char (char *someVar) and you write to it, where does what you have written go if you have not initialised the pointer?
     
  5. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #5
    The only way I see to get an initialized NSSavePanel:
    Code:
    savePanel = [NSSavePanel savePanel];
    -Lee
     
  6. liptonlover thread starter macrumors 6502a

    Joined:
    Mar 13, 2008
    #6
    ok, looking back at my hillegas book I remember init stuff now. Where do I do initializing though? Does it need its own special method, or can I do it in the header?
     
  7. MrFusion macrumors 6502a

    Joined:
    Jun 8, 2005
    Location:
    West-Europe
    #7
    Not in the header, for certain.
    Where you do it, is up to you.
    Variables declared in the header are accessible everywhere in your class. These are usually initialized in an init method. Variables local to your method are allocated and initialized in the method you need them.

    Don't forget to release these when you are done with them!

    header:
    Code:
    
    NSString *stringOne;
    NSString *stringTwo;
    
    Implementation:

    Code:
    
    - (id) init {
    	self = [super init];
    	if (self != nil) {	
              stringOne = [[NSString alloc] initWithString:@"one"]; //don't forget to release
              stringTwo = [NSString stringWithString:@"two"]; // you did not initialized this one. has been done for you
            }
     return self;
    }
    
    -(void) printAll {
     NSString *stringThree = [[NSString alloc] initWithString:@"3"]; //don't forget to release
     NSString *stringFour = [NSString stringWithString:@"4"]; // you did not initialized this one. has been done for you
           
     NSLog(@"%@ %@ %@",stringOne,stringTwo,stringThree,stringFour);
     [stringThree release];
    
     [stringOne release]; // global variable is released, and replaced in the next line
     stringOne = [[NSString alloc] initWithString:@"new"]; //don't forget to release, if you comment this line out, your program should crash
     NSLog(@"%@ %@",stringOne,stringTwo,stringFour);
    }
    -(void) dealloc {
      [stringOne release];
     [super dealloc];
    }
    
    
     
  8. liptonlover thread starter macrumors 6502a

    Joined:
    Mar 13, 2008
    #8
    ok I have an - (id) init {} method, and I put:
    [savePanel init];
    savePanel=[NSSavePanel savePanel];
    return self;

    This does not give any errors, but when I run the program and click save it freezes. More accurately in xcode it says loading gdb debugger when I click save. And the savepanel never comes up.
     
  9. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #9
    Don't do this. For the majority of the time, save/open panels really only need to be created when you're going to use them. For example:

    Code:
    - (IBAction)saveFile:(id)sender {
        NSSavePanel *savePanel = [NSSavePanel savePanel];
        // customize savePanel here...
        if ([savePanel runModal] == NSOKButton)
            // user chose a file accessible via [savePanel filename]
    }
     
  10. liptonlover thread starter macrumors 6502a

    Joined:
    Mar 13, 2008
    #10
    ok thanks :) but will that fix my problem of it not running?

    Also, some init questions if you don't mind.

    Does [super init]; cover all initializing that's needed for every object?

    Do I need [outlet init]; ?
     
  11. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #11
    Most likely, unless you're not showing us all of your code :)

    Whatever initXXX method you're overriding in your subclass, always call [super initXXX]. Although with NSObject this isn't really necessary, but it's a good habit to get into.

    No. any IButlet connected in Interface Builder gets initialized automagically by the nib-loading process. If you need to do any further customization of nib objects, do it in awakeFromNib.
     
  12. liptonlover thread starter macrumors 6502a

    Joined:
    Mar 13, 2008
    #12
    sorry I meant pointer. Like [savePanel(my pointer) init];
     
  13. liptonlover thread starter macrumors 6502a

    Joined:
    Mar 13, 2008
    #13
    Sorry for double post but I made the corrections, so I'd like to share the working product in case anyone else needs help with it

    #import <Cocoa/Cocoa.h>

    @interface AppController : NSObject {
    //don't create a pointer to the savepanel here.
    IBOutlet id savingPanel;
    IBOutlet id text;
    IBOutlet id myWindow;
    }
    - (IBAction)savePressed:(id)sender;
    @end



    #import "AppController.h"

    @implementation AppController
    - (IBAction)savePressed:(id)sender {
    //create the pointer and create the object it points to.
    NSSavePanel *savePanel=[NSSavePanel savePanel];
    //the most basic easiest method to open an NSSavePanel. Check out the class file to see the additional options.
    [savePanel runModal];
    }

    - (void)awakeFromNib {
    }

    - (id)init {//init file.
    [super init];
    return self;
    }
    @end


    Thanks for your help guys!
     
  14. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #14
    Each class is different. You need to read the docs. In this instance with NSSavePanel, you only call the savePanel method, not alloc/init. Other objects you will have to call alloc/init. It depends on what the designated initializer is for each class.

    Don't call init by itself. You use alloc/init together. alloc creates the object in memory, and init initializes it.

    I would suggest reading Introduction to Memory Management Programming Guide for Cocoa
     

Share This Page