Passing Variables

Discussion in 'Mac Programming' started by Spike099, Jun 28, 2007.

  1. macrumors regular

    Joined:
    Feb 18, 2007
    Location:
    Canada
    #1
    So this is my noobish problem.

    The situation:

    2 NIBs:
    MainMenu
    AddPersonPanel

    Within MainMenu contains an instance of appController, appController contains an variable for AddPersonController. When a button is pressed on the window of mainmenu, it shows the panel of AddPersonPanel. AddPersonPanel is a custom class of AddPersonController.

    So, when I click the add button in the AddPersonPanel, it calls the add function in AddPersonController. I have a NSImage within this class that I need to be passed to the appController.

    I have tried making an instance of appController in the AddPersonPanel and linking the add button to the add function in appController, but it never executes.

    How can I return the image to the appController, or call a function from appController and pass it a variable.

    Thanks guys, let me know if this needs more detail or even some code.
     
  2. macrumors member

    Joined:
    Jun 25, 2007
    Location:
    London
    #2
    Not really sure I understand what you're after, and as a noob myself, take all this with a pinch of salt.

    When I needed to pass something to a new item within an arrayed controller, I created a subclass of NSArrayController and reimplemented the -(id)newObject method.

    I also added IBOutlets for the UI controls that would act as the inputs for the info. In my case text boxes, In yours the image. Then linked these in IB

    In my reimplemented newObject, I then passed the values to the new object to set it up.

    In your app controller have your array controller be of the type of your subclassed array controller, and in IB change the custom class of the declared instance of the array controller to your sub classed version.

    That way when you use the add method, the correct info is passed.

    I'm sure that's all very badly explained.
     
  3. macrumors 6502

    Joined:
    Dec 6, 2006
    #3
    It sounds like he doesn't actually want to send the NSImage to window, but the otherway round. And you can't do that with IB.

    There are a variety of ways. You could add a sheet, and call the sheet. When the sheet ends, a method is called you can use to retrieve the data.

    The other way is probably similar to what you are currently doing. You press a button which sends an event to what ever method you have in your main class to do something. You show the screen. You need to show it as a modal screen, so you can retrieve data afterwards. I can't remember the code for this, it isn't difficult.

    Or use NSDocument in a bizarre and twisted way.
     
  4. macrumors G4

    Eraserhead

    Joined:
    Nov 3, 2005
    Location:
    UK
    #4
    I'm not convinced that subclassing NSArrayController or using a sheet is the best way to pass this image.

    In my experience you only need to subclass stuff when absolutely necessary, and in this case I don't think it's needed.

    You may find CoreData would be a good approach for what you are doing, then you can store the image in an NSManagedObject and then you can use valueForKey to recover it.

    It would probably be helpful for you to post the project file so we can take a look, I for one am very confused about what you are trying to do, so this post probably doesn't make sense.

    If you don't want to post the source, send me a PM with it, or describe what you want to do, not which classes you are using as that will enable us to help you better.
     
  5. thread starter macrumors regular

    Joined:
    Feb 18, 2007
    Location:
    Canada
    #5
    Hey, I will do so when I get home... Still another 7 hours before that though.

    Thanks for your input guys. I will have to read up about Core Data in the meantime.
     
  6. macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #6
    If I understand the problem correctly: you have two objects, appController and AddPersonController, and you want the add method in AddPersonController to pass an NSImage to appController. Is that right?

    If so, you just need to add an IBOutlet to AddPersonController, and connect it to appController. Then simply add a
    Code:
    -(void) setImage:(NSImage*) theImage;
    method to appController and call that from the add method in AddPersonController.

    (From your message, it seems the two objects might be in two different nibs. I don't know if you can connect outlets between nibs, but I'm guessing you can).
     
  7. thread starter macrumors regular

    Joined:
    Feb 18, 2007
    Location:
    Canada
    #7
    Yeah, I don't think that is possible.

    The issue is that appController is initialized in MainMenu. So when I initialize the new NIB, I would have to pass it a pointed to the appController so that I can call it's methods.

    In appController I tried

    Code:
    [addPersonController showWindow2:self];
    In addPersonController I had

    Code:
    - (void)showWindow2:(id)sender
    {
     appController = sender;
     [self showWindow:self];
    }
    As I go on about this, I forget what happened. I'm pretty sure this did not work. I will have to further test this when I get home.

    From the responses, there is alot I can try in attempt to achieve this. However, it may be more beneficial to keep the panel in the same NIB anyway.
     
  8. macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #8
    There's a good chance the code you posted would crash. If appController is a member/instance variable of AddPersonController, you need to retain the pointer in that method. Something like:

    Code:
    - (void)showWindow2:(id)sender
    {
        if (appController != sender)
        {
            [appController release];
            appController = [sender retain];
        }
        [self showWindow:self];
    }
    
    That may or may not be the problem, but it's something to be aware of. Feel free to post the code/project or snippets if you'd like us to take a look.
     
  9. thread starter macrumors regular

    Joined:
    Feb 18, 2007
    Location:
    Canada
    #9
    whooleytoo, I will definitely post the code tonight. Don't have access to my Mac from here :(.
     
  10. macrumors 68020

    Krevnik

    Joined:
    Sep 8, 2003
    #10
    Windows and their panels should probably be in the same NIB. Otherwise you get to do the dirty work of figuring out how to get objects from the loaded NIB.

    For smaller apps, I would say the rule of thumb is: Main Window and its panels/sheets should be in one NIB (or Document Window), and things like a Preferences window should get its own NIB (since it should just hook into UserDefaults).
     
  11. thread starter macrumors regular

    Joined:
    Feb 18, 2007
    Location:
    Canada
    #11
    Okay I got it working. I was thinking of using a sheet to perform this task but had not yet looked into making sheets. So... I am displaying the panel(now a window) using a sheet. Now that I can pass the image, a whole new series of problems have been presented with resizing and cropping :D . I'm sure you'll all be hearing about them soon enough.

    In my adventures I found:

    Code:
    [NSBundle loadNibNamed: @"MyCustomSheet" owner: self];
    I have not looked into this yet. But from the look of it I can load a sheet from another NIB using the current window as it's owner. If I ever really want the sheet in another NIB, maybe NSBundle is where I should be looking.

    Thanks guys for helping me out. Much appreciated.
     
  12. macrumors 6502

    Joined:
    Mar 31, 2005
    Location:
    London, England
    #12
    Yes, that's right. It's a good idea to put the sheet in a separate nib, so that you can delay loading it into memory until you actually need it. Your custom window or window controller can be the owner of the nib.

    It's true that (as Krevnik says) putting each window, sheet, panel etc into its own nib restricts the connections you can make in interface builder, but that can actually be a good thing as it forces you to keep your objects in a hierarchy rather than a spaghetti.
     
  13. thread starter macrumors regular

    Joined:
    Feb 18, 2007
    Location:
    Canada
    #13
    Now loading Nib

    Alright I now have my sheet in a separate Nib as my appController was just getting too messy. The nib file is been loaded via NSNib

    In appController.h
    Code:
    NSArray *addPersonPanel;
    In appController.m
    Code:
    - (IBAction)openSheet:(id)sender
    {
    	addPersonPanel = [self loadMyNibFile];
    	[NSApp beginSheet:[addPersonPanel ***********]
    	   modalForWindow:mainWindow
    		modalDelegate:self
    	   didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
    		  contextInfo:NULL];
    }
    
    - (NSArray*)loadMyNibFile
    {
        NSNib*      aNib = [[NSNib alloc] initWithNibNamed:@"AddPersonPanel" bundle:nil];
        NSArray*    topLevelObjs = nil;
    	
        if (![aNib instantiateNibWithOwner:self topLevelObjects:&topLevelObjs])
        {
            NSLog(@"Warning! Could not load nib file.\n");
            return nil;
        }
    	[aNib release];
    	
            [topLevelObjs makeObjectsPerformSelector:@selector(release)];
    	
    	return topLevelObjs;
    }
    I really just don't understand top level objects, I know it's everything contained in the Nib(minus file owner and first responder). However how do I know what index to issue my actions.

    Ex, where ********* is in the method opedSheet.
     
  14. macrumors G4

    Eraserhead

    Joined:
    Nov 3, 2005
    Location:
    UK
    #14
    Each nib file needs to have a separate controller, it should be a subclass of NSWindowController.

    In that Controller you have an init method which looks like this, where NewNib is the name of the nib file you are trying to load:
    Code:
    -(id)init{
    	[super init];
    	[NSBundle loadNibNamed:@"NewNib"
    					 owner:self];
    	//more custom code goes in here.
    	return self;
    }
    

    With regards to this [addPersonPanel ***********] piece of code I have no idea what you are trying to do, you can only load one sheet at a time.
     
  15. thread starter macrumors regular

    Joined:
    Feb 18, 2007
    Location:
    Canada
    #15
    Okay, so my variable in appController.h should be

    Code:
    NSWindowController *addPersonPanel
    then initialize in appController.m and load sheet like this?

    Code:
    addPersonPanel = [[NSWindowController alloc] init];
    	[NSApp beginSheet:addPersonPanel
    	   modalForWindow:mainWindow
    		modalDelegate:self
    	   didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
    		  contextInfo:NULL];
    
    This makes sense to me. I was going through a tone of documentation and some examples, but nothing ever said to make the nib's file owner a NSWindowController. Nor did they say to put the init code in the Nib file it's self.

    I'll have to wait and try when I get home. Thanks.
     
  16. macrumors G4

    Eraserhead

    Joined:
    Nov 3, 2005
    Location:
    UK
    #16
    You still are barking up the wrong tree, you beginSheet on the IBOutlet pointing to the window in the NSWindowController.

    Go and read chapter 22 of the Aaron Hillegass book, it explains sheets perfectly well.

    If you don't own a copy of it, I suggest that you buy it.
     
  17. thread starter macrumors regular

    Joined:
    Feb 18, 2007
    Location:
    Canada
    #17
    Okay I got it working finally. The whole Nib thing through me off and was causing me to forget other things. Thanks for your patience Eraserhead.
     
  18. macrumors G4

    Eraserhead

    Joined:
    Nov 3, 2005
    Location:
    UK
    #18
    Thats OK :).
     

Share This Page