ryanmasondavies / Bindings

A lightweight iOS library inspired by Cocoa Bindings.
MIT License
20 stars 1 forks source link

Default trigger? #3

Closed sibljon closed 11 years ago

sibljon commented 11 years ago

In the example,

// Create a bind between person's name attribute and the text field's text
BNDBinding *binding = [[BNDBinding alloc] initWithSource:[personVC person] sourceKeyPath:@"name" destination:[personVC textField] destinationKeyPath:@"text"];

// Add a trigger to update the binding when KVO notifications are sent for person's name property
BNDTrigger *trigger = [[BNDKVOTrigger alloc] initWithKeyPath:@"name" object:[personVC person] delegate:binding];
[binding addTrigger:trigger];

The trigger could be implicitly set up within -[BNDBinding initWithSource:...]. What would you say to a convenience method that sets up the trigger along with the binding? I believe this would fit the most common case: where the trigger's object is the same as the binding's source. Say:

- (id)initWithTriggerForSource:(id)source sourceKeyPath:(NSString *)sourceKeyPath destination:(id)destination destinationKeyPath:(NSString *)destinationKeyPath;
ryanmasondavies commented 11 years ago

I started working on an example project to get a better understanding of how to use bindings with an iOS architecture I'm working on (I'll post it to my blog when I've thought it all through). I wanted to bind a text field to a model property:

BNDBinding *binding = [[BNDBinding alloc] initWithSource:textField sourceKeyPath:@"text" destination:model destinationKeyPath:keyPath];
BNDTrigger *kvoTrigger = [[BNDKVOTrigger alloc] initWithKeyPath:@"text" object:textField delegate:binding];
BNDTrigger *notificationTrigger = [[BNDNotificationTrigger alloc] initWithNotificationCenter:[NSNotificationCenter defaultCenter] notificationName:UITextFieldTextDidChangeNotification sender:textField delegate:binding];
[binding addTrigger:kvoTrigger];
[binding addTrigger:notificationTrigger];

Boy that is a lot of boilerplate code!

(As a sidenote, it turns out that text fields use KVO to notify observers of change via setText: and notifications for changes made by the user, so both trigger types are required to bind a model to a text field.)

I agree that there is a need for reduction when interacting with Bindings, however I would argue that implicit creation of a default trigger is not the way to go. While it is the simplest solution, doing so would mix object graph construction with application logic, and add 'magic' to the class that would not be immediately obvious to newcomers.

On the subject of common cases, I think we should go one step further and provide a factory for creating bindings based on specific object types. This would allow new developers to use Bindings without needing to be aware of particulars such as text fields emitting both KVO events and notifications, as well as removing most boilerplate code from the application layer. E.g:

BNDBindingFactory *factory = [[BNDBindingFactory alloc] init];
[bindings addBinding:[factory bindingForTextField:textField toKeyPath:@"name" onModel:model]];

What do you think of this sort of solution?