Basic info about outlets
-
I *think* I understand about outlets and actions .. but now I am not so
sure.
Specifically, if I set (NSWindow *)documentWindow as an Outlet in my main
nib and I declare in MyDocument.h file:
interface MyDocument:NSDocument {
IBOutlet NSWindow *documentWindow;
}
...
- (void) someMethod:documentWindow;
and in MyDocument.m file:
- (void) someMethod {
// some operation that accesses a property of documentWindow
}
Okay, documentWindow is typed as a outlet in the main nib and in the
interface,.h, file ... and I have control-dragged from the FileOwner to the
title bar of the Window, selecting "documentWindow" as the Outlet. But,
just exactly HOW does the actual documentWindow object get passed so that
someMethod can look at one of its properties?
This question is oriented to "behind the scenes".
Thanks in advance>
John Love -
Yep, you're basically correct, sounds right to me.
When the nib is loaded, <documentWindow> will point to ("refer to")
the window object.
someMethod is able to simply use the variable <documentWindow> because
that is an instance variable of the MyDocument object, and all methods
of MyDocument are able to use the object's ivars as if they were
locally declared. This is one of the main reasons that OOP is a useful
way to program.
so someMethod could then message the window itself, for example:
- (void) someMethod
{
// set a property:
[documentWindow setTitle:@"Arrooooggahh!!"];
// read a property:
NSRect wFrame = [documentWindow frame];
}
If you're asking *how* this works, the answer lies in the Obj-C
runtime. Basically all of an object's methods are implicitly passed a
pointer to the object itself (self) as a hidden parameter to the
function that the method is wrapping. The compiler thus generates code
that makes use of this implicit parameter, so the real code is really
doing the equivalent of:
void someMethod( NSDocument* self )
{
setTitle( self->documentWindow, @"string" );
}
underneath, it's all procedural ;-) (I'm simplifying, it's not
literally quite like this, Find out more here: file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html)
.
hth,
G.
On 15 May 2008, at 9:30 pm, John Love wrote:> I *think* I understand about outlets and actions .. but now I am not
> so
> sure.
>
> Specifically, if I set (NSWindow *)documentWindow as an Outlet in my
> main
> nib and I declare in MyDocument.h file:
>
> interface MyDocument:NSDocument {
> IBOutlet NSWindow *documentWindow;
> }
> ...
>
> - (void) someMethod:documentWindow;
>
> and in MyDocument.m file:
>
> - (void) someMethod {
> // some operation that accesses a property of documentWindow
> }
>
> Okay, documentWindow is typed as a outlet in the main nib and in the
> interface,.h, file ... and I have control-dragged from the FileOwner
> to the
> title bar of the Window, selecting "documentWindow" as the Outlet.
> But,
> just exactly HOW does the actual documentWindow object get passed so
> that
> someMethod can look at one of its properties?
>
> This question is oriented to "behind the scenes".
>
> Thanks in advance>
>
> John Love -
Hm ...I would have though the runtime would just do dependency/
reference injection.
And the procedural code has a (hidden) reference/parameter to the
object instance - that would be "self".
cheers
--
Torsten
On May 15, 2008, at 13:53, Graham Cox wrote:> Yep, you're basically correct, sounds right to me.
>
> When the nib is loaded, <documentWindow> will point to ("refer to")
> the window object.
>
> someMethod is able to simply use the variable <documentWindow>
> because that is an instance variable of the MyDocument object, and
> all methods of MyDocument are able to use the object's ivars as if
> they were locally declared. This is one of the main reasons that OOP
> is a useful way to program.
>
> so someMethod could then message the window itself, for example:
>
> - (void) someMethod
> {
> // set a property:
>
> [documentWindow setTitle:@"Arrooooggahh!!"];
>
> // read a property:
>
> NSRect wFrame = [documentWindow frame];
> }
>
>
> If you're asking *how* this works, the answer lies in the Obj-C
> runtime. Basically all of an object's methods are implicitly passed
> a pointer to the object itself (self) as a hidden parameter to the
> function that the method is wrapping. The compiler thus generates
> code that makes use of this implicit parameter, so the real code is
> really doing the equivalent of:
>
> void someMethod( NSDocument* self )
> {
> setTitle( self->documentWindow, @"string" );
> }
>
> underneath, it's all procedural ;-) (I'm simplifying, it's not
> literally quite like this, Find out more here: file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html)
> .
>
> hth,
>
>
> G.
>
>
>
> On 15 May 2008, at 9:30 pm, John Love wrote:
>
>> I *think* I understand about outlets and actions .. but now I am
>> not so
>> sure.
>>
>> Specifically, if I set (NSWindow *)documentWindow as an Outlet in
>> my main
>> nib and I declare in MyDocument.h file:
>>
>> interface MyDocument:NSDocument {
>> IBOutlet NSWindow *documentWindow;
>> }
>> ...
>>
>> - (void) someMethod:documentWindow;
>>
>> and in MyDocument.m file:
>>
>> - (void) someMethod {
>> // some operation that accesses a property of documentWindow
>> }
>>
>> Okay, documentWindow is typed as a outlet in the main nib and in the
>> interface,.h, file ... and I have control-dragged from the
>> FileOwner to the
>> title bar of the Window, selecting "documentWindow" as the Outlet.
>> But,
>> just exactly HOW does the actual documentWindow object get passed
>> so that
>> someMethod can look at one of its properties?
>>
>> This question is oriented to "behind the scenes".
>>
>> Thanks in advance>
>>
>> John Love -
I did say I was simplifying. Write for the audience.
The procedural code doesn't have a hidden 'self', it's completely
explicit:
id objc_msgSend(id theReceiver, SEL theSelector, ...);
G.
On 15 May 2008, at 11:21 pm, Torsten Curdt wrote:> Hm ...I would have though the runtime would just do dependency/
> reference injection.
> And the procedural code has a (hidden) reference/parameter to the
> object instance - that would be "self". -
Furthermore, if you want to see it in action a little more:
If you create an object with an outlet like so:
IBOutlet NSWindow *window
and also give it methods like so:
- (NSWindow *)window;
- (void)setWindow:(NSWindow *)aWindow;
When loading the nib, rather than directly setting the instance
variable, the system is kind enough to call the accessor method for
you instead. So, you can stick a breakpoint on -setWindow: and watch
it happen. There's no real magic, just variables getting hooked up.
Mike.
On 15 May 2008, at 14:21, Torsten Curdt wrote:> Hm ...I would have though the runtime would just do dependency/
> reference injection.
> And the procedural code has a (hidden) reference/parameter to the
> object instance - that would be "self".
>
> cheers
> --
> Torsten
>
> On May 15, 2008, at 13:53, Graham Cox wrote:
>
>> Yep, you're basically correct, sounds right to me.
>>
>> When the nib is loaded, <documentWindow> will point to ("refer to")
>> the window object.
>>
>> someMethod is able to simply use the variable <documentWindow>
>> because that is an instance variable of the MyDocument object, and
>> all methods of MyDocument are able to use the object's ivars as if
>> they were locally declared. This is one of the main reasons that
>> OOP is a useful way to program.
>>
>> so someMethod could then message the window itself, for example:
>>
>> - (void) someMethod
>> {
>> // set a property:
>>
>> [documentWindow setTitle:@"Arrooooggahh!!"];
>>
>> // read a property:
>>
>> NSRect wFrame = [documentWindow frame];
>> }
>>
>>
>> If you're asking *how* this works, the answer lies in the Obj-C
>> runtime. Basically all of an object's methods are implicitly passed
>> a pointer to the object itself (self) as a hidden parameter to the
>> function that the method is wrapping. The compiler thus generates
>> code that makes use of this implicit parameter, so the real code is
>> really doing the equivalent of:
>>
>> void someMethod( NSDocument* self )
>> {
>> setTitle( self->documentWindow, @"string" );
>> }
>>
>> underneath, it's all procedural ;-) (I'm simplifying, it's not
>> literally quite like this, Find out more here: file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html)
>> .
>>
>> hth,
>>
>>
>> G.
>>
>>
>>
>> On 15 May 2008, at 9:30 pm, John Love wrote:
>>
>>> I *think* I understand about outlets and actions .. but now I am
>>> not so
>>> sure.
>>>
>>> Specifically, if I set (NSWindow *)documentWindow as an Outlet in
>>> my main
>>> nib and I declare in MyDocument.h file:
>>>
>>> interface MyDocument:NSDocument {
>>> IBOutlet NSWindow *documentWindow;
>>> }
>>> ...
>>>
>>> - (void) someMethod:documentWindow;
>>>
>>> and in MyDocument.m file:
>>>
>>> - (void) someMethod {
>>> // some operation that accesses a property of documentWindow
>>> }
>>>
>>> Okay, documentWindow is typed as a outlet in the main nib and in the
>>> interface,.h, file ... and I have control-dragged from the
>>> FileOwner to the
>>> title bar of the Window, selecting "documentWindow" as the
>>> Outlet. But,
>>> just exactly HOW does the actual documentWindow object get passed
>>> so that
>>> someMethod can look at one of its properties?
>>>
>>> This question is oriented to "behind the scenes".
>>>
>>> Thanks in advance>
>>>
>>> John Love -
On May 15, 2008, at 15:32, Graham Cox wrote:> I did say I was simplifying. Write for the audience.
I know, I know ...just think of me as one of the guys asking a
question after a presentation ;)
cheers
--
Torsten -
But, just exactly HOW does the actual documentWindow object get passed so that
someMethod can look at one of its properties?
This question is oriented to "behind the scenes"
For the current version of Interface Builder, see
- (void)connectOutlet:(NSString *)outletofSourceObject:(id)sourcetoDestinationObject:(id)destination
of the IBDocument class in the InterfaceBuilderKit framework.
In the current version of Interface Builder, the precise mechanism for storing connection information is not documented and therefore considered an implementation detail. However, in previous versions of Interface Builder, it worked like the following:
There is/was a class called IBConnector which looked something like this
@interface IBConnector : NSObject <NSCoding>
{
id source;
NSString *outletName;
id destination;
}
- (void)setSource:(id)anObject;
- (void)setOutletName:(NSString *)aName;
- (void)setDestination:(id)anObject;
- (void)connect;
@end
When you drag a connection in IB, a new instance of IBConnector is created, initialized with a source, outlet name, and destination accordingly, and archived into the .nib file.
When the nib file is tested in IB or loaded into your application at run-time, the IBConnector instances are unarchived just like every other object in the nib. Once unarchived, each IBConnector instance's source and destination instance variables are restored to a reference to the corresponding unarchived objects. [That is just how archiving and unarchiving graphs of objects works. Read up on archiving for details].
As part of the nib loading process but before -awakFromNib is sent to any objects unarchived from the nib, the connect message is sent to each unarchived IBConnection instance.
The -connect method of IBConnector is implemented something like this
- (void)connect
{
Ivar ivar = class_getInstanceVariable([source class], [outletName UTF8String]);
object_setIvar(source , ivar, destination);
}
See http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Ref
erence/reference.html for information about class_getInstanceVariable() and object_setIvar(). The source code for the runtime is also available.
Once the connections are all made, the IBConnector instances are no longer needed and may be deallocated.
Then -awakeFromNib is called for every object unarchived from the nib and incidentally also the "File's Owner" object. Because the connections were all restored before -awakeFromNib, it is safe to use the connections in your implementation of -awakeFromNib.
Does that answer you "behind the scenes" question ? -
That's interesting :)
And I think I answered the completely wrong question. duh.
G.
On 16 May 2008, at 12:08 am, Erik Buck wrote:> But, just exactly HOW does the actual documentWindow object get
> passed so that
> someMethod can look at one of its properties?
>
> This question is oriented to "behind the scenes"
>
> For the current version of Interface Builder, see
> - (void)connectOutlet:(NSString *)outletofSourceObject:
> (id)sourcetoDestinationObject:(id)destination
>
> of the IBDocument class in the InterfaceBuilderKit framework. -
Thanks, Erik ... the "behind the scenes" explanation was exactly what I
needed ... will take lots of time to absorb it.
One last thing ... an administrative thing, of sorts ... is there a means of
replying to, e.g., this "Basic info about outlets", without going to my
email; i.e., using this Web Site as a means of replying.
Thanks in advance,
John Love


