Example code programming Objective-C with Cocoa in Xcode and Interface Builder (Leopard)

19: Two way communication between NSView and NSControl using dummy class

Communicate out of an NSView using an IBOutlet and a dummy Class.

Problem: you want to be able to send messages from a Custom NSView to its controller and from the controller to the Custom View. The Custom View can get the Id of the Control and the Control the Id of the Custom View but you can' have each class have an include of the other classes header file (because of circularity).

Solution: include a header in the Custom NSView to a dummy class that has the same name and arguments as the method you want to call. When you now send the message Cocoa's Dynamic Messaging will find the controller by its stored Id.

Implementation.

Create a new project in XCode: File->New Project->Cocoa Application
Call it: 019-NSControl-NSView

Now create the classes: MyControl and MyDummyControl of type NSObject and MyCustomView of type NSView.
Code these as shown below and save.

// MyControl.h // 019-NSControl-NSView // #import <Cocoa/Cocoa.h> #import "MyCustomView.h" @interface MyControl : NSObject { IBOutlet MyCustomView *myCustomViewObjOutlet; IBOutlet NSTextField *myTextFieldOutlet; NSString *myControlString; } - (IBAction)assignTextFieldToCVS:(id)pId; // CVS = CustomViewString - (IBAction)showCVSInTextField:(id)pId; - (NSString *)returnNTextField; - (void)assignStringToTextField:(NSString *)pString; @end // MyControl.m // 019-NSControl-NSView // #import "MyControl.h" @implementation MyControl - (IBAction)assignTextFieldToCVS:(id)pId; // CVS = CustomViewString { [myCustomViewObjOutlet setMyString:[myTextFieldOutlet stringValue]]; } // end assignTextFieldToCVS - (IBAction)showCVSInTextField:(id)pId; { NSString * zString = [myCustomViewObjOutlet myString]; [myTextFieldOutlet setStringValue:zString]; } // end readCustViewString - (NSString *)returnNTextField; { NSString * zString = [myTextFieldOutlet stringValue]; return zString; } // end returnNTextField - (void)assignStringToTextField:(NSString *)pString { [myTextFieldOutlet setStringValue:pString]; } // end assignStringToTextField @end // MyDummyControl.h // 019-NSControl-NSView // // The existence of this class fools the compiler // into allowing us to talk to MyControl. // #import <Cocoa/Cocoa.h> @interface MyDummyControl : NSObject { } - (NSString *)returnNTextField; - (void)assignStringToTextField:(NSString *)pString; @end // MyDummyControl.m // 019-NSControl-NSView // #import "MyDummyControl.h" @implementation MyDummyControl // method to fool compiler into letting us talk to MyControl - (NSString *)returnNTextField { return(@"string from MyDummyControl"); } // end returnNTextField - (void)assignStringToTextField:(NSString *)pString { NSLog(@"MyDummyControl %@",pString); } // end assignStringToTextField @end // MyCustomView.h // 019-NSControl-NSView // #import <Cocoa/Cocoa.h> #import "MyDummyControl.h" // Note: one can do without the dummy class MyDummyControl but // a) this makes the fact that we are using an unconventional mechanism explicit // b) it prevents compiler warnings. // @interface MyCustomView : NSView { IBOutlet id myControlObj; // IBOutlet MyControl * myControlObj; NSString *myString; } -(NSString *)myString; -(void)setMyString:(NSString *)pString; @end // MyCustomView.m // 019-NSControl-NSView // #import "MyCustomView.h" @implementation MyCustomView - (id)initWithFrame:(NSRect)frame { if ((self = [super initWithFrame:frame]) == nil) { NSLog(@"MyCustomView initWithFrame failed"); return self; } // end if myString = @"Hi from CustomView"; return self; } // end initWithFrame -(void)mouseUp:(NSEvent *)pTheEvent { // Note: in the past one needed to use coersion // myString = [(MyDummyControl *)myControlObj myNSTextFieldString]; //[(MyDummyControl *)myControlObj assignNSTextFieldString:@"mouseUp"]; [self setMyString: [myControlObj returnNTextField]]; [myControlObj assignStringToTextField:@"Thank you from mouseUp"]; } // end mouseUp -(NSString *)myString; { return myString; } // end myString -(void)setMyString:(NSString *)pString; { // prevent an NSInvalidArgumentException if pString is nil. if(pString) { myString = [[NSString alloc]initWithString: pString]; } else { myString = @""; } // end if } // end setMyString - (void)drawRect:(NSRect)pNSRect { [[NSColor yellowColor] set]; NSRectFill( pNSRect ); } // end drawRect @end

Bring up Interface Builder by double clicking on MainMenu.nib.

Drag a Custom NSView, two NSButtons, an NSTextField and a label onto the window and name them as shown.

XCode,Interface Builder - Do the layout

Interface Builder: Do the layout

Drag an NSObject onto the MainMenu.xib panel.
Select it and set its class to MyControl.
Note the IBAction and IBOutlets.

XCode,Interface Builder - Set class of NSObject

Interface Builder: Set class of NSObject to MyControl

Link them as shown.

XCode,Interface Builder,Link MyControl to MyCustomView

Link MyContol IBActions and IBOutlets to their targets, especially note the link to to MyCustomView

Select MyCustomView and link its IBOutlet to MyControl.

XCode,Interface Builder, Link IBOutlet of Custom NSView to MyControl

Link IBOutlet of Custom NSView to MyControl

Save and Run.

XCode,Interface Builder, Run

Run: clicking the Custom View causes it first to call the controller to return textField data and second, to call the controller to put data in the textField. The buttons generate calls from the controller to the CustomView routines

If you want to download the code

Click the Download Link to obtain 019-NSControl-NSView.zip file of this whole OS X 10.5 Leopard program.

Download 019-NSControl-NSView.zip (2.3 MB)

Useful Links



Please send me your comments

If you include your e-mail I may reply!  

Page last modified: 18:58 Sunday 12th. May 2013

Julius Guzy

Paintings & Drawings

  • Link to painting of Star of Bethlehem flowers

animatedPaint