58: Delegates, Custom Classes, NSTextField

Problem: We want to make sense of delegates and use them in our programming because the literature tells us they're a good idea.

I have found it very difficult to get my head around the idea of delegates. My difficulty is that I cannot visualise what one of these things looks like. For instance, the documentation and various authors refer to delegates as helper objects. Say that I want to build a delegate helper object, e.g. for NSTextField. What I then find is that I have to implement the delegate code within my subclass of NSWindowControl, i.e. the thing that is supposed to be doing the controlling has now become a helper - i.e. subservient to the thing being helped. That is, in this case my helper object is not a helper object but a controller. The helper objects don't actually exist. All one is doing is putting some code in one of one's own objects which has to be of an appropriate class, and then hooking it up as a delegate. Confused? Well join the club.

However, I think I might finally have cracked it and it all has something to do with aspects of technical english - namely Humpty Dumpty's view of words as meaning exactly what he wants them to mean, no more and no less. The problem is then in trying to understand what Humpty Dumpty means especially if you think he is using words to mean what most people think them to mean and not the new fangled meanings he has actually given them.

So here for what it is worth is my moment of blinding clarity and it came in part from the blog: Rick's World where he describes how to make one's own delegate. That was in the past one of my difficulties. I went looking for delegates, I went looking on how to implement them - after all they sound like a very good idea, and only found confusion. So here, after a bit of head scratching around Ricks article and other stories, is my conclusion about what one of these things is and what it looks like.

What a Delegate Is and What it Looks Like.

The delegate's methods are defined as a protocol, what Java programmers would call an abstract interface. For instance, define the file MyDelegateMethodsProtocol.h and insert the following code:

// MyDelegateMethodsProtocol.h #import <Cocoa/Cocoa.h> @interface NSObject (MyDelegateProtocol) - (void)myDelegateMethod; @end

Now define both the delegating class and the delegate class as subclasses of the class extended by the protocol, in this case NSObject.

// MyDelegatingClass.h #import <Cocoa/Cocoa.h> @interface MyDelegatingClass : NSObject { IBOutlet id delegate; } @property (assign) IBOutlet id delegate; - (IBAction)callADelegateMethod:(id)pSenderId; @end // MyDelegatingClass.m #import "MyDelegatingClass.h" @implementation MyDelegatingClass @synthesize delegate; - (IBAction)callADelegateMethod:(id)pSenderId { [delegate myDelegateMethod]; // calls the delegate } // end callADelegateMethod @end // MyDelegateClass.h #import <Cocoa/Cocoa.h> @interface MyDelegateClass : NSObject { } @end // MyDelegateClass.m #import "MyDelegateClass.h" @implementation MyDelegateClass - (void)myDelegateMethod { NSLog(@"MyDelegateClass myDelegateMethod"); } // end myDelegateMethod @end

In MainMenu.xib drag two NSObject objects onto the main panel and in the inspector set them to MyDelegatingClass and MyDelegateClass respectively. In the connections pane for MyDelegatingClass set MyDelegateClass as the delegate, set the button to the receiving action callADelegateMethod and make MyDelegatingClass the Application delegate so it does not get disappeared by the Garbage Collector. Build and Run.

So all of that stuff in the documentation about how delegation means you don't have to sub-class classes etc is in a sense just that little bit deceptive because effectively the classes have already done that. It is just that they have been defined to have that extra bit of capacity. So we could define the delegate business something like this:

If two classes A, B, share a common superclass and a protocol is defined upon that superclass with abstract method X then if an instance of class A contains the id of an instance of class B and class B implements method X then instance A can call method X in instance B. The instance of class B is referred to as the delegate of the instance of class A.

There you are.
Here is a project which shows this explicitly.

// CommonClass.h #import <Cocoa/Cocoa.h> @interface CommonClass : NSObject { } @end // define the protocol #import "CommonClass.h" @interface CommonClass (MyProtocol) - (void)abstractMethod; @end // CommonClass.m #import "CommonClass.h" @implementation CommonClass @end // Delegator.h #import <Cocoa/Cocoa.h> #import "CommonClass.h" @interface Delegator : CommonClass { IBOutlet id delegate; } @property (assign) IBOutlet id delegate; // to be called from button in interface window - (IBAction)internalFunction:(id)pSender; @end // Delegator.m #import "Delegator.h" @implementation Delegator @synthesize delegate; // called from button in interface window - (IBAction)internalFunction:(id)pSender { [self.delegate abstractMethod]; } @end // Delegate.h #import <Cocoa/Cocoa.h> #import "CommonClass.h" @interface Delegate : CommonClass { } @end // Delegate.m #import "Delegate.h" @implementation Delegate - (void)abstractMethod { NSLog(@"thats all folks!"); } @end

Go into Interface Builder, drag two objects onto MainMenu.xib, call them Delegator and Delegate in the Inspector. Drag a button onto the panel. Select the Delegator, connect the delegate outlet with the Delegate, connect the action with the button and make Delegator a delegate of Application so to keep the Garbage Collector at bay. Save and run.
That's all folks!

Lets now see how this new found understanding of ours works out in practice, for instance, if we want to get data out of an NSTextField. To do that we need to belong to the protocol implementing subclass of the class of which NSTextField is a subclass, viz one of NSControl : NSView : NSResponder : NSObject. The one we want is a subclass of NSControl because that employs the delegate method controlTextDidChange. That is, if we write the method controlTextDidChange within a subclass of NSControl, e.g. NSWindowController and in IB make our object a "delegate" of the NSTextField object then we will be called whenever the text changes.

Here's some code to get text from an NSTextField when it changes

// MyWindowController.h #import <Cocoa/Cocoa.h> @interface MyWindowController : NSWindowController { IBOutlet NSTextField * nsTextFieldObj; } @property (assign) IBOutlet NSTextField * nsTextFieldObj; @end // MyWindowController.m #import "MyWindowController.h" @implementation MyWindowController @synthesize nsTextFieldObj; - (void)controlTextDidChange:(NSNotification *)aNotification { NSLog(@"MyWindowController controlTextDidChange %@",[nsTextFieldObj stringValue]); } @end

Go into Interface Builder, put an NSTextField onto the Window, drag an object onto the MainMenu.xib, set it to MyWindowController in the Inspector, then in the Connections pane make it into a delegate of the NSTextField and of the Application (so the Garbage Collector won't eat it up). Save everything and run.

XCode,Interface Builder, NSTextField set the delegate connections

Interface Builder set the delegate connections

Yes, I think people got carried away by the high falutin' sound of "delegate" and "helper object" and thereby made it a bit of a learning nightmare for the rest of us. Because the thing is a straightforward (and clever) idea. The definition of a given class includes calls to methods defined in an abstract interface (aka protocol) which one can avail oneself of if one wants.

If you want to download the code

Click the Download Link to obtain 058-Delegates.zip file of all three of these OS X 10.6.1 Leopard programs.

058-Delegates.zip (7MB)



Please send me your comments

If you include your e-mail I may reply!  

Page last modified: 11:57 Monday 7th. November 2011

Julius Guzy

Paintings & Drawings

  • Link to drawing made from painting by Rubens of the Feast of Venus

animatedPaint