Setting the outlets of objects

Dragging objects from the object library into the interface builder, buttons, text fields, tables whatever you require we can rapidly construct a UI. To connect one object to another setting its outlets, ^ drag this time, from the object that needs to know to the object that it needs to know about.

Labels

Labels can be set to NSTextField objects, giving your program the ability to alter their content. Right clicking upon the object that contains the NSTextField and then select the field from the outlets and drag over to the Label object in the interface display.

Text Field

Text fields like labels are backed by NSTextField objects, the text filed connection is slightly different, the text filed will accept user input to set its content and is read from within the program so as to input data, where the label was solely outputting.

Buttons

We need to set both the target and the action of buttons. Right click upon the object that contains the button action, in the left side panel of the interface builder, select that action and drag over to the button in the display to set.

Else drag from a button into the code of a class within the assistant window, either drop onto an existing action or into a life of the file, this will open up the dialogue box to create the required action.


#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

@interface RandomController : NSObject
{   
	IBOutlet NSTextField *textField;
}
- (IBAction)generate:(id)sender;
- (IBAction)seed:(id)sender;
@end
			

awakeFromNib

Objects can override the awakeFromNib function in order to run code before runtime.


- (void)awakeFromNib
{    
	NSDate *now;    
	now = [NSDate date];    
	[textField setObjectValue:now];
}
			

NSTableView

dataSource

The NSTableView is used for displaying tables, it requires a dataSource object, this object is expected to have some specific methods; We say that, the data source must conform to the NSTableDataSource's informal protocol. For which it must implement, at the very least, the two following methods.


- (id)tableView:(NSTableView *)aTableView 
		objectValueForTableColumn:(NSTableColumn *)aTableColumn
		row:(NSInteger)rowIndex;

- (void)tableView:(NSTableView *)aTableView
		setObjectValue:(id)anObject
		forTableColumn:(NSTableColumn *)aTableColumn
		row:(NSInteger)rowIndex;

// for editable cells...
- (void)tableView:(NSTableView *)aTableView
		setObjectValue:(id)anObject
		forTableColumn:(NSTableColumn *)aTableColumn
		row:(NSInteger)rowIndex;
			

First, you will set the dataSource outlet of the NSTableView to be the desired delegate, the class that implements the require methods. Select the NSTableView. Control-click in the table view to bring up the Connections panel, then drag from the dataSource outlet to the applications desired delegate class for the dataSource.

If you do not see dataSource in the inspector, you have selected NSScrollView, not NSTableView inside it. just click in the interior of the table view until the title of the Connection panel says NSTableView.

Select the table view, then in the inspector panel on the right hand side of the interface builder, set the table cell type and the desired number of column's, cell based is much simpler than view based.

Now create a tableView outlet inside of the delegate class, to connect the table view outlet to. For example: Make sure that you have the table view selected and Control-drag to the class declaration in the header file.

We need also to set the inner table view object to have what will usually be the same delegate as the entire object.

Key Values Coding and Key Value Observing

The NSObject type from which all Objective-C class inherit, lends to its inheritors two functions for acting upon the classes internal members, for example: given a custom made class with a member name setName can be called to set the members value and name to retrieve it.

By declaring these method in our class we can override them in order to inject functionality..

Sliders

The somewhat cumbersome NSInteger type that is required to have our get and set methods becomes more obviously useful when we see how these methods are used by an object such as the NSSlider as it calls the set and the get methods to both know its initial position and to update it whenever it is moved.

If the backing value for the slider is changed elsewhere in a program, then the sliders backing type must also be updated. We can do this by explicitly trigger the notification of the observers.

				
- (IBAction)incrementSlider:(id)sender
{
	[self willChangeValueForKey:@"value"];
	value++;
	NSLog(@"value is now %d", value);
	[self didChangeValueForKey:@"value"];
}
				
			
Or we can use key-value coding
				
- (IBAction)incrementSlider:(id)sender
{
	NSNumber *n = [self valueForKey:@"value"];
	NSNumber *npp = [NSNumber numberWithInt:[n intValue] + 1];
	[self setValue:npp forKey:@"value"];
}
				
			
Or the accessor method
				
- (IBAction)incrementSlider:(id)sender
{
	[self setValue:[self value] + 1];
}
				
			

Rather than declaring set and get methods manually, the objective-c language will make them for us automatically when we create a variable as a property rather than just an instance.

				
@interface KvcFunAppDelegate : NSObject 
{
	int value;
}
@property (assign) IBOutlet NSWindow *window;
@property (readwrite, assign) int value;
- (IBAction)incrementValue:(id)sender;
@end
				
			

Attributes of a Property

readwrite or readonly, the default is readwrite, a property marked with readonly gets no get or set methods. To describe how the set method works a property can include one of the following attributes:

If your program is multithreaded your attributes might also include nonatomic or atomic. By default the @synthesize will generate accessors with this attribute. If you know that your property does not need to be atomic, you can assign to it the nonatomic attribute and negate the overhead.


If a property matches a incidence variable you can use @synthesize, xcode will by default use an underscore at the start of the underlying variables name _value.

				
@synthesize value;
				
			

If you would like to add your own prefix to the instance variable, you can do so like this:

				
@synthesize value = _my_value;
				
			

Key Paths

Objects that are related can be accessed using key paths, this is effectively the . notion used within the @"key.path.accessor.syntax" There are also operators that can be applied within the request. average = [this valueForKeyPath:@"@avg.some.value"];

Commonly used operators:

bindings

Having learned about key paths we can now take a look at bindings.

				
[textField bind:@"value" toObject:employeeController 
		withKeyPath:@"arrangeObjects.@avg.expectedRaise"
		options:nil];
				
			

Bindings can also be created automatically by making connections in the interface builder. Create a document based project and then within the document.xib, add an NSArrayController and set its class, then add to the controller any specific key values that are required, such as the names of required attributes from the underlying class. Next open the array controllers bindings inspector and find the content array binding and expand it. Check 'bind to' then 'File's Owner', leave the controller key empty but set the Model Key Path to the desired array instance.