PDA

View Full Version : Bindings, lots of glue code?




Sijmen
Mar 20, 2008, 01:05 PM
I was writing an MVC app today. I noticed that to expose a binding, you have to write a lot of code for each one, all which are much alike. Like you have to observe value changes, store the observable and the key path, etc.

Am I overlooking something here or is exposing bindings a pain? Is there a reason why there's no standard API to keep two properties (or KVC/KVO compliant attributes) in sync?


To clarify, just in case, here's one of my classes to see what I'm talking about.


//
// DimpBaseView.h
// Dimp
//
// Created by Sijmen Mulder on 20-03-08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@class Bone;

@interface DimpBaseView : NSView
{
id rootBoneBindingObject;
id currentTimeBindingObject;

NSString *rootBoneBindingPath;
NSString *currentTimeBindingPath;

Bone *rootBone;
float currentTime;
}

@property (readwrite, retain) Bone *rootBone;
@property (readwrite) float currentTime;

@end


//
// DimpBaseView.m
// Dimp
//
// Created by Sijmen Mulder on 20-03-08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "DimpBaseView.h"

static void *RootBoneBindingContext = (void *)@"RootBoneBindingContext";
static void *CurrentTimeBindingContext = (void *)@"CurrentTimeBindingContext";

@implementation DimpBaseView

- (void)bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
if ([binding isEqualToString:@"rootBone"])
{
if (rootBoneBindingObject)
[self unbind:binding];

rootBoneBindingObject = observable;
rootBoneBindingPath = keyPath;

[rootBoneBindingObject addObserver:self forKeyPath:keyPath options:0 context:RootBoneBindingContext];
}
else if ([binding isEqualToString:@"currentTime"])
{
if (currentTimeBindingObject)
[self unbind:binding];

currentTimeBindingObject = observable;
currentTimeBindingPath = keyPath;

[currentTimeBindingObject addObserver:self forKeyPath:keyPath options:0 context:CurrentTimeBindingContext];
}
else
{
[super bind:binding toObject:observable withKeyPath:keyPath options:options];
}
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == RootBoneBindingContext)
{
[self setValue:[rootBoneBindingObject valueForKey:rootBoneBindingPath] forKey:@"rootBone"];
}
else if (context == CurrentTimeBindingContext)
{
[self setValue:[currentTimeBindingObject valueForKey:currentTimeBindingPath] forKey:@"currentTime"];
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

- (void)unbind:(NSString *)binding
{
if ([binding isEqualToString:@"rootBone"])
{
[rootBoneBindingObject removeObserver:self forKeyPath:rootBoneBindingPath];

rootBoneBindingObject = nil;
rootBoneBindingPath = nil;
}
else if ([binding isEqualToString:@"currentTime"])
{
[currentTimeBindingObject removeObserver:self forKeyPath:currentTimeBindingPath];

currentTimeBindingObject = nil;
currentTimeBindingPath = nil;
}
else
{
[super unbind:binding];
}
}

- (Bone *)rootBone
{
return rootBone;
}

- (void)setRootBone:(Bone *)value
{
if (rootBone == value)
return;

rootBone = value;

if (rootBoneBindingObject)
[rootBoneBindingObject setValue:value forKeyPath:rootBoneBindingPath];

[self didChangeValueForKey:@"rootBone"];
[self setNeedsDisplay:YES];
}

- (float)currentTime
{
return currentTime;
}

- (void)setCurrentTime:(float)value
{
if (currentTime == value)
return;

currentTime = value;

if (currentTimeBindingObject)
[currentTimeBindingObject setValue:[NSNumber numberWithFloat:value] forKeyPath:currentTimeBindingPath];

[self didChangeValueForKey:@"rootBone"];
[self setNeedsDisplay:YES];
}

@end



kainjow
Mar 20, 2008, 02:19 PM
I've never done custom bindings before, but it looks about right. Not too much extra code, but I'm sure you could simplify a lot of that down, since you seem to be doing a lot of similar code in each if statement (but don't forget readability > cleverness ;)). But the advantage is you do your glue code only once, and use bindings elsewhere.


By the way, is your last name really Mulder? That's awesome :cool:

Sijmen
Mar 23, 2008, 06:17 AM
I've never done custom bindings before, but it looks about right. Not too much extra code, but I'm sure you could simplify a lot of that down, since you seem to be doing a lot of similar code in each if statement (but don't forget readability > cleverness ;)). But the advantage is you do your glue code only once, and use bindings elsewhere.


By the way, is your last name really Mulder? That's awesome :cool:

Thanks foor looking :) my last name is Mulder indeed.

I feel this way of binding is a bit tedious. It requires 3 variables and some 20 lines of code per binding. Ough. But just wanted to make sure that this is how it's supposed to be, and I'm not missing on something obvious.

Eraserhead
Mar 23, 2008, 07:15 AM
I don't usually bother in my coding for D&D Manager, and I just use set/get methods when the built in bindings aren't enough.

springframework
Apr 2, 2008, 01:03 PM
hey, can someone post the most simple project that used bindings? preferably a project that only contains one simple binding.

just something simple like a variable that is bound to a text field. so the text field is auto filled with the variable value, and when the text field changes the variable gets changed to the new value of the text field.

After reading the documentation on bindings, they seem poor to me. i would really like see if anyone finds them useful to use. and i would like to know if anyone actually uses them throughout their application.

Sijmen
Apr 2, 2008, 01:08 PM
Using existing bindings (like a text field) is pretty easy. This tutorial (http://developer.apple.com/documentation/Cocoa/Conceptual/CurrencyConverterBindings/01introduction/chapter_1_section_1.html) might be what you're looking for.

cruzrojas
Apr 2, 2008, 08:41 PM
hey, can someone post the most simple project that used bindings? preferably a project that only contains one simple binding.

http://www.macresearch.org/cocoa_for_scientists_part_xiii_in_a_bind

enjoy.