Wednesday, April 25, 2012

Cocoa: Binding. GUI application without outlets


Outlet in Cocoa is a persistent reference to a GUI control. For example, it is a common way to create the outlet to the text field and change the text in this field via the outlet. Now, in 64-bit Xcode, you add a property with IBOutlet keyword, synthesize it, and set new text via that property:

1. In interface declaration:
@property (retainIBOutlet NSTextField * text;

2. In the implementation section:
@synthesize text;

3. Set new text to the text field:

text.stringValue = @"Hello, World!";

4. Get value:

NSString* str = text.stringValue;

Same can be done without coding. Sometimes it can be needed and interesting. Let's make a test application:
1. Create new Mac OS X Cocoa project in Xcode:

I named the project as TextNoOutlet (shown on the screenshots above).
2. In the application delegate class we add a string property:

Initially the application delegate class declared as (TextNoOutletAppDelegate.h file):

#import

@interface TextNoOutletAppDelegate : NSObject {
    NSWindow *window;
}

@property (assignIBOutlet NSWindow *window;

@end

Replace it for:

#import

@interface TextNoOutletAppDelegate : NSObject

@property (assignIBOutlet NSWindow *window;
@property (copy) NSString *text;

@end


Control-S to save the header file. Alt-Cmd-Up to switch to the m-file. Synthesize the property:

#import "TextNoOutletAppDelegate.h"

@implementation TextNoOutletAppDelegate

@synthesize window;
@synthesize text;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application 
}

@end


Here I added only one line shown in bold. Control-S here to save the modification.

3. In Interface Builder (click twice on the MainWindow.xib file) will put the Text Field on the prototype window. Let's put Label under this text field. Arrange the size and locations.

4. The binding.
Select the text field in the prototype window. Press Command-4 to open the Binding Inspector:

In the Value section check the checkbox and set "text" in the Modal Key Path field.


Select the label. Command-3 to switch to the Binding Inspector. Check the checkbox and modify the Modal Key Path in the same way as for the text field.

Save your work in Interface Builder (Control-S or Save in the File menu).
5. Build and Run the program:


Try to type a text in the text field, press Enter and see the text reflected in the label.

Let's apply the binding to the application window:
In Interface Builder select the window object in the Document window, press Command-4 to switch to the Binding Inspector and bind the title of the window in the same way as the label before:


Save the change and Build and Run the program:


I'd Like to show one more interesting example with the slider control.  Same principle: we will add a property, for example value to the application delegate class and bind it with the slider control and a label. The property added to the application delegate is shown in the bold:

#import

@interface TextNoOutletAppDelegate : NSObject

@property (assignIBOutlet NSWindow *window;
@property (copy) NSString *text;
@property (assign) NSInteger value;

@end


It should be synthesized in the implementation file:

#import "TextNoOutletAppDelegate.h"

@implementation TextNoOutletAppDelegate

@synthesize window;
@synthesize text;
@synthesize value;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application 
}

@end


In Interface Builder I add the slider and one more Label. Then I bind the slider with "value" property:


I'd like to set "Continuos" for the slider control:


Now I select the new label in the prototype window and will bind it in a bit different way - via "Value with Pattern"


Save my work, switch to Xcode and Build and Run my program:

This "simplification" of the GUI work (do not use outlet for a GUI control and connect many GUI controls to the same property) is possible because of the nice feature of Objective-C 2.0 - Key-Value Coding or KVC. It is a simple protocol allowing to set and get values indirectly. In the first example, that uses the outlet, I call a method to get or to set values to/from the text field. Then, in the next examples, I specify a key that is used by Cocoa to figure out which property match up to this key: the property text was added to the application delegate class and key 'text' was used to bind the GUI controls with the application delegate.

No comments:

Post a Comment