Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > Aaron Hillegass' Chapter 9 Challenge 2

Aaron Hillegass' Chapter 9 Challenge 2
Thread Tools
Electrophoretic
Fresh-Faced Recruit
Join Date: Jul 2006
Status: Offline
Reply With Quote
May 12, 2006, 03:12 AM
 
Hi Guys,

This is my first post!

I've been lurking around here for a while gathering tips and such for my foray into Cocoa development. I'm having a great time!

I am having a problem with Chapter 9 Challenge 2 in Aaron Hillegass' Cocoa Programming for Mac OS X book which everyone knows so well.

The challenge is simply to add a custom 'About Panel' to the RaiseMan application by using NSBundle.

Here is my code...

Code:
AboutPanelController *aboutPanel; BOOL successful = [NSBundle loadNibNamed:@"AboutPanel" owner:aboutPanel]; [aboutPanel makeKeyAndOrderFront];
So... It doesn't work... 'AboutPanelController' may not respond to makeKeyAndOrderFront.

So I tried many variations and looked back through the chapter and etc etc. My AboutPanelController is just an (uninstantiated in the nib) subclass of NSWindowController (as I believe it explains in the chapter a few pages earlier) and I have added the following method to the AppController class:

- (IBAction)showPreferencePanelid)sender;
- (IBAction)showAboutPanelid)sender;

showPreferencePanel was already there from the chapter (and also is uninstantiated in the nib) and I added showAboutPanel and connected it to the appropriate menu item. Some variations just gave me 'invalid selector' type errors, other variations, such as the one I listed above, kick me into the debugger when I click the menu item.

I must be missing something small or I'm on the totally wrong track... Any help you can throw my way would be greatly appreciated!

Thanks a lot,
funduk
     
Chuckit
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status: Offline
Reply With Quote
May 12, 2006, 03:25 AM
 
The variable aboutPanel is never set to anything. It's basically pointing to a random point in the program's memory. Thus, it can't be the owner of anything until you actually create an object to go in the variable.
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
     
Electrophoretic  (op)
Fresh-Faced Recruit
Join Date: Jul 2006
Status: Offline
Reply With Quote
May 12, 2006, 12:07 PM
 
I figured that's why I got kicked into the debugger. I changed it to this:

Code:
AboutPanelController *aboutPanel = [[AboutPanelController alloc] initWithWindowNibName:@"AboutPanel"]; BOOL successful = [NSBundle loadNibNamed:@"AboutPanel" owner:aboutPanel]; if( successful ) { [aboutPanel makeKeyAndOrderFront]; }
And nothing explodes, but I still get 'AboutPanelController may not respond to makeKeyAndOrderFront' along with the following error when I click the about... button:

-[AboutPanelController makeKeyAndOrderFront]: selector not recognized [self = 0x388690]

Like I said above AboutPanelController is a subclass of NSWindowController and it has no methods and no members. Do I need to reimplement the makeKeyAndOrderFront method? I don't know where I'd begin to do that and the chapter doesn't mention anything of the sort, nor does it include any substantial information that might help me do so.

Thanks a lot for your help so far btw!
funduk
     
Chuckit
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status: Offline
Reply With Quote
May 12, 2006, 01:14 PM
 
NSWindowController doesn't have a makeKeyAndOrderFront method — that's in NSWindow. Try showWindow: instead.
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
     
Wevah
Senior User
Join Date: Nov 2001
Location: State of Denial
Status: Offline
Reply With Quote
May 12, 2006, 05:11 PM
 
(Also, NSWindow's method is makeKeyAndOrderFront: (note the colon; it takes an argument).)

But the end answer is what Chuckit said.
[Wevah setPostCount:[Wevah postCount] + 1];
     
Electrophoretic  (op)
Fresh-Faced Recruit
Join Date: Jul 2006
Status: Offline
Reply With Quote
May 12, 2006, 06:31 PM
 
Thanks for your replies guys... Hillegass says to use makeKeyAndOrderFront, and I reading the problem incorrectly? He says to use NSBundle and says something like 'hint, send it the message makeKeyAndOrderFront'.

I'm not trying to argue or anything, I just want to find out what exactly is happening, my main concern isn't the actual challenge, it's knowing what is going on!

Thanks again and I'll play with your suggestions tonight after work.

-- funduk
     
Chuckit
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status: Offline
Reply With Quote
May 12, 2006, 07:03 PM
 
You could do [[aboutPanel window] makeKeyAndOrderFront:self]. That's probably what he was thinking.
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
     
Electrophoretic  (op)
Fresh-Faced Recruit
Join Date: Jul 2006
Status: Offline
Reply With Quote
May 12, 2006, 08:26 PM
 
Great so I tried that stuff you guys offered up and here's what I ended up with for the showAboutPanel: method:

Code:
AboutPanelController *aboutPanel = [[AboutPanelController alloc] initWithWindowNibName:@"AboutPanel"]; [NSBundle loadNibNamed:@"AboutPanel" owner:aboutPanel]; [[aboutPanel window] makeKeyAndOrderFront:self]; // also tried ...Front:aboutPanel]; NSLog(@"opened aboutpanel");
The application compiles and runs without errors but when I click the menu item nothing happens.

RaiseMan[598] Nib file loaded (about)
RaiseMan[598] opened aboutpanel

so the nslog statement i put in the end there works great, but nothing happens!

also I've changed a bunch of the [NSBundle ...] lines code a few times and nothing seems to make any difference, infact if I remove the line altogether nothing changes! Is this challenge/chapter just a load or something? It doesn't seem to be very... coherent. Why am I not just adding the window the same way I added the preference window? What am I using the NSBundle for, i never assign it's value to anything but a BOOL, yet it never fails (and likely never will) so what's the point?

Maybe I'm just not getting the point of the challenge but it seems kind of pointless / undirected. 'Use this method (which is incorrect) to do this (which you dont need to do)...'... ?

Regardless, thanks a lot for your help guys, this forum is a huge wealth of information!

-- funduk
     
Angus_D
Addicted to MacNN
Join Date: Mar 2000
Location: London, UK
Status: Offline
Reply With Quote
May 13, 2006, 10:23 AM
 
Well, you don't need to use a separate NSWindowController for the about panel, maybe he was just expecting you to add an outlet (of type NSWindow) to your existing controller object. Then you can just do [aboutWindow makeKeyAndOrderFront:self].
     
Electrophoretic  (op)
Fresh-Faced Recruit
Join Date: Jul 2006
Status: Offline
Reply With Quote
May 14, 2006, 11:48 AM
 
Ok well I've decided to give up on this challenge. Some of Angus' advice gave me some ideas and I played with many variations but in the end I ended up with:

Code:
[NSBundle loadNibNamed:@"AboutPanel" owner:aboutPanel]; [aboutPanel makeKeyAndOrderFront:self];
and in the header file I have an 'outlet' of type NSWindow called aboutPanel (as Angus says, in the existing controller).

This setup gives no errors and seems to work great. I try the menu option and:

Code:
RaiseMan[1219] *** -[NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil value
So, I'm just not going to bother with this challenge, since it gives no errors I'll just leave it there in my app if I ever decide to come back to fix it but the challenge is so poorly worded and doesn't really fit with the chapter at all. I've had no problems with any other challenges so far in the book (including the next 2 chapters') and so I am finding this one a waste of my (and, consequently, your) time.

Thanks for all your input... Anyone else reading this someday who can't get the challenge working, dont bother

-- funduk
     
Chuckit
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status: Offline
Reply With Quote
May 14, 2006, 02:41 PM
 
I know you've moved on, but just for posterity, that code is slightly off. The owner is supposed to be self (or the existing controller if that code isn't called from it), not aboutPanel, since the controller is supposed to own aboutPanel. That's the reason it crashes.
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
     
imelv
Fresh-Faced Recruit
Join Date: Jul 2006
Status: Offline
Reply With Quote
May 23, 2006, 03:06 AM
 
I don't know if anyone is still following this thread but I came across it because I was having a similar problem with the same Challenge in the book. Anyway, after a few days cursing and trying to find out where my understanding was lacking I was finally able to sort the problem out. The following is a quick summary of my solution in case anyone else has the same trouble...

The first thing that I should say is that my solution incorporates a subclass of NSWindowController to control the About nib file that was created (About.nib) that simply shows a Panel with a bit of text on it. While the use of a controller, I think, makes for a more flexible design in case I want to make the About panel more exciting, it is not the simplest solution. Last night I found an old article on the O'Reilly Network that provides a solution using only the existing application controller (in the case of RaiseMan, that would be AppController). This article contains a few typos but did help and can be read here. The section that you want is called "A Custom About Panel" and appears about halfway down the page.

OK. Moving on to my own solution. The summary of the solution I implemented is as follows and, while it works, I don't guarantee that it is perfect:

1. Create your About.nib file in Interface Builder

2. Create a subclass of NSWindowController in XCode (I called mine AboutController). The class doesn't need any instance methods or variables declaring since it inherits what it needs from NSWindowController but I did override the init: method to include super=[super initWithWindowNibName:@"About"]; - I don't know if this was necessary or not.

3. Drag the header file for the controller (AboutController.h) from XCode and into About.nib in Interface Builder

4. Open the Custom Class inspector settings of File's Owner and set it to the controller class (AboutController)

5. Control-drag from File's Owner to the Panel and set the File's Owner to connect the File's Owner window instance variable to the NSPanel (NOTE: this is what I hadn't done originally and, ultimately, was the cause of 2-days of woe).

6. In the application controller header file (AppController.h), declare a new instance variable of type About Controller (e.g. AboutController *aboutController;) and a new instance method to trigger the About panel to be displayed (e.g. - (IBAction)showAboutPanel:(id)sender;).

7. Drag the revised AppController.h file into the MainMenu.nib file in Interface Builder so that its definition is updated.

8. Control-drag from the About menu item in MainMenu.nib to the existing instance of AppController and set its target to your new method showAboutPanel.

9. Back in XCode, implement the new showAboutPanel method so that it creates a new instance of the AboutController, if one does not already exist, load the NIB file for the About panel and show it on-screen. My code for this method is as follows:

- (IBAction)showAboutPanel:(id)sender
{
if (!aboutController) {
NSLog(@"AboutController isn't setup - calling init");
aboutController = [[AboutController alloc] init];
}

[NSBundle loadNibNamed:@"About"
owner:aboutController];
[[aboutController window] makeKeyAndOrderFront:nil];
}

10. Build, run and (hopefully) enjoy a feeling of zen-like peace when it works

As best as I can tell, the main problems were ensuring that the File's Owner in the About.nib file was set to the controller and that the AboutController's window instance variable (which is key when it comes to displaying the panel) is linked to the Panel. Once that was achieved you simply need to create an instance of the controller, call its window method so that it returns a pointer to the Panel (which is a subclass of NSWindow) and then call the NSWindow method makeKeyAndOrderFront:(id)sender method to make the damned panel appear. Where I had been going wrong was in my assumption that I needed to add an instance variable in my AboutController to point to the Panel and setting the target of that variable to the Panel rather than using the window variable that, I presume, is inherited from NSWindowController. Technically, that approach could still work (I think) but since a suitable variable already exists I elected to make use of the existing window instance variable, which I presume is correct given the number of inherited methods that make use of the window variable.

Anyway, I hope that all makes sense and that this helps anyone else who has the same trouble.
     
madeonamac
Fresh-Faced Recruit
Join Date: Aug 2006
Status: Offline
Reply With Quote
Aug 12, 2006, 05:25 PM
 
There is a much easier solution to this, I believe. This is my solution:
1) Create a new nib named AboutPanel.
2) Create a new panel, add some text, and most importantly, in the Inspector for File's Owner, change the Custom Class to NSWindowController
3) Add a - (IBAction)showAboutPanel: (id)sender; method in the AppController.h file and add the following instance variable to the object: 'NSWindowController *aboutPanel;'. This is to avoid memory leaks by assigning new NSWindowControllers each time we open a the About Panel (I believe that this is necessary, though someone may know better)
4) Open the MainMenu.nib file, drag in the AppController.h file, and connect the 'About RaiseMan' menu option to the 'showAboutPanel' target.
5) implement that action as follows:
[FONT="Courier New"]-(IBAction)showAboutPanel: (id)sender
{
if (!aboutPanel)
aboutPanel = [[NSWindowController alloc] initWithWindowNibName: @"About"];
BOOL successful = [NSBundle loadNibNamed:@"AboutPanel"
owner:aboutPanel];
if (successful)
NSLog(@"Loaded the nib file successfully);
else
NSLog(@"Failed to load nib file");
[[aboutPanel window] makeKeyAndOrderFront:sender];
}[/FONT]

--------
This should work now. There is no need to create a new class file inheriting from NSWindowController -- there is no model logic and so a plain-old controller will do just fine.
-I hope that helps somebody.
     
   
 
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Top
Privacy Policy
All times are GMT -4. The time now is 09:19 AM.
All contents of these forums © 1995-2017 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.8 © 2000-2017, Jelsoft Enterprises Ltd.,