PDA

View Full Version : Small issue with "AppController"




mdeh
Oct 10, 2009, 02:41 PM
I am trying to dissect "Sketch-112" and in the process wrote something small which is not working quite the way I wish.

SetUP.

AppController with 1 IBOutlet, (An NSTextField) which is instantiated in the nib. I just left the word "label" intact on the NSTextField.

In the init method of AppController this:

NSColor * g = [ NSColor greenColor];
NSString *s = @"Hello World";
NSTextField *f = [[NSTextField alloc]init];
[f setBackgroundColor:g];
[f setStringValue:s];
NSLog(@"The value of TextField \"f\" is: %@",[f stringValue]);
[self setTextField: f];

and the relevant setter this:

- (void) setTextField: (NSTextField*) t
{
if ( _textField == t)
return;
[_textField release];
[t retain];
_textField = t;
NSLog(@"The value of TextField \"_textField\" is: %@",[_textField stringValue]);


}


Now the output is this:

The value of TextField "f" is: Hello World
The value of TextField "_textField" is: Hello World
The value of TextField "_textField" is: Label

So, the problem seems to be that the word "Label" is added after the setter is called. Could anyone possibly explain the issue and how to get around this?

Thanks ...in advance...as usual.



petron
Oct 10, 2009, 03:08 PM
Hi, again Mdeh, I see that you still are fighting with xcode.

I looked at it for a while and do not see any bug, but I have a question.

The first LOG for "f" is OK
the second LOG for "_terxtField" is OK and I assume it is from the setter.
The third one is a misterium. Do you know where is it comming from ?

Seems like forom another place or a next call to setter.

Please add a NSLog of the receiving parameter, it may help. I usually when staring a debugging add prefix to NSLog informing me from which method a NSLog has been executed. Like:
NSLog(@"setTextField: The value of the TextField....");

Good Luck
/petron

chown33
Oct 10, 2009, 03:26 PM
AppController with 1 IBOutlet, (An NSTextField) which is instantiated in the nib. I just left the word "label" intact on the NSTextField.

In the init method of AppController this:

NSColor * g = [ NSColor greenColor];
NSString *s = @"Hello World";
NSTextField *f = [[NSTextField alloc]init];
[f setBackgroundColor:g];
[f setStringValue:s];
NSLog(@"The value of TextField \"f\" is: %@",[f stringValue]);
[self setTextField: f];


The init method of AppController is invoked when the nib is loaded. This creates a text-field containing "Hello world" and assigns it to the IBOutlet _textField. Remember, all this happens in init.

The nib-loading machinery then proceeds to make all the archived objects defined in the nib, and assign them to their designated IBOutlets. So a new NSTextField is created, this time containing the text "Label", because that's what the nib says. That object is then assigned to the IBOutlet, overwriting the object created in init.

The nib-loading machinery will use a setter method if one exists, as determined by the name of the target, which is "_textField" in this case. The "_" is first stripped, the first letter is capitalized, and then "set" is prefixed. The result is "setTextField", and there is a method of that name, so it's invoked. That's where the second NSLog comes from.


What you're doing is simply wrong. You shouldn't be creating and assigning IBOutlets in init. The whole point of an IBOutlet is that its object is defined by the nib. You have to choose one way to create member objects: either create them in code, or use the nib. You can't do both.

If you have properties of IBOutlets that you want to change in code, such as assigning a background color, the appropriate place for that is awakeFromNib, which is only called AFTER all IBOutlets have been connected from the nib.

Also, you say you're modifying "Sketch-112", but you don't provide a URL or other reference. Do you mean Apple's sample code:

http://developer.apple.com/mac/library/samplecode/Sketch-112/index.html

It would also help if you explain what you want to accomplish. You wrote that it's not working the way you wish, but you never said what way you wish it to work.

mdeh
Oct 10, 2009, 06:26 PM
The init method of AppController is invoked when the nib is loaded. This creates a text-field containing "Hello world" and assigns it to the IBOutlet _textField. Remember, all this happens in init.

The nib-loading machinery then proceeds to make all the archived objects defined in the nib, and assign them to their designated IBOutlets. So a new NSTextField is created, this time containing the text "Label", because that's what the nib says. That object is then assigned to the IBOutlet, overwriting the object created in init.

The nib-loading machinery will use a setter method if one exists, as determined by the name of the target, which is "_textField" in this case. The "_" is first stripped, the first letter is capitalized, and then "set" is prefixed. The result is "setTextField", and there is a method of that name, so it's invoked. That's where the second NSLog comes from.

Yes...thanks chown. I figured something like this was happening.


What you're doing is simply wrong. You shouldn't be creating and assigning IBOutlets in init. The whole point of an IBOutlet is that its object is defined by the nib. You have to choose one way to create member objects: either create them in code, or use the nib. You can't do both.

Makes sense. I guess that's the problem when one is just playing around. But...it's all part of the learning curve. So, thank you for your insight.



If you have properties of IBOutlets that you want to change in code, such as assigning a background color, the appropriate place for that is awakeFromNib, which is only called AFTER all IBOutlets have been connected from the nib.

Well...I will have to try that again, as I placed the code there but had a similar result. But...I probably did something incorrectly.


Also, you say you're modifying "Sketch-112", but you don't provide a URL or other reference. Do you mean Apple's sample code:

http://developer.apple.com/mac/library/samplecode/Sketch-112/index.html

Exactly.



It would also help if you explain what you want to accomplish. You wrote that it's not working the way you wish, but you never said what way you wish it to work.

:-)

Good point. This all started with a challenge in Hillegass's book, creating ovals in a document based app. (Chapter 18) . I take those challenges seriously, else all that happens when you end the book is that you know what's in the book!!! I realized that even though I had done things with Document based apps in the book, I really did not have a good grasp of the architecture, and having spent hours looking online, many people recommended this example. The tangent from this example , of course, was looking at the issue of properties and ivars, and where exactly to "expose" them...another poorly defined term. So, to answer your really short question with this incredibly long answer, I wrote this just to test my understanding of properties/ivars. My expectation was that I could set the label to read "Hello world" on a green background!! :-) But, your insight helps, for which I thank you.

Further stuff. Out of curiosity, in order to understand this control a little better, I moved the relevant code to "awakeFromNib", but still get the same result ie the word "label" is still not replaced. Am I still missing something?

Output now is:

MethodName init:
MethodName setTextField:
The value of TextField "_textField" is: label
MethodName awakeFromNib:
The value of TextField "f" is: Hello World
MethodName setTextField:
The value of TextField "_textField" is: Hello World


Note that I added a macro to ID the method