View Full Version : Passing Variables

Jun 28, 2007, 06:52 AM
So this is my noobish problem.

The situation:

2 NIBs:

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.

Jun 28, 2007, 08:19 AM
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.

Jun 28, 2007, 08:31 AM
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.

Jun 28, 2007, 08:49 AM
So this is my noobish problem.
Thanks guys, let me know if this needs more detail or even some code.

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.

Jun 28, 2007, 08:54 AM
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.

Jun 28, 2007, 11:26 AM
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 -(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).

Jun 28, 2007, 11:59 AM
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

[addPersonController showWindow2:self];

In addPersonController I had

- (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.

Jun 28, 2007, 12:19 PM
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:

- (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.

Jun 28, 2007, 01:25 PM
whooleytoo, I will definitely post the code tonight. Don't have access to my Mac from here :(.

Jun 28, 2007, 01:52 PM
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.

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).

Jun 28, 2007, 07:12 PM
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:

[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.

Jun 29, 2007, 06:31 PM
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.

Jul 5, 2007, 08:54 PM
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
NSArray *addPersonPanel;

In appController.m
- (IBAction)openSheet:(id)sender
addPersonPanel = [self loadMyNibFile];
[NSApp beginSheet:[addPersonPanel ***********]

- (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.

Jul 6, 2007, 03:39 AM
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:

[super init];
[NSBundle loadNibNamed:@"NewNib"
//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.

Jul 6, 2007, 09:40 AM
Okay, so my variable in appController.h should be

NSWindowController *addPersonPanel

then initialize in appController.m and load sheet like this?

addPersonPanel = [[NSWindowController alloc] init];
[NSApp beginSheet:addPersonPanel

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.

Jul 6, 2007, 02:43 PM
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 (http://www.amazon.com/Cocoa-Programming-Mac-OS-2nd/dp/0321213149), it explains sheets perfectly well.

If you don't own a copy of it, I suggest that you buy it.

Jul 6, 2007, 04:50 PM
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.

Jul 7, 2007, 05:50 AM
Thanks for your patience Eraserhead.

Thats OK :).