views:

110

answers:

2

I would like to be able to use bindings to keep my GUI synchronized to a dynamically loaded object, but as soon as I replace the object in question with another one of the same type the bindings break and the GUI stops updating. Here's some code to help you understand what I mean:

In my interface I have an instance variable to hold the object in question:

@interface AppDelegate : NSObject {
    CustomObject *anObject; // This object has a "NSString *textValue" property
}

Then in my implementation I instantiate the object:

- (id) init {
    self = [super init];
    if (self != nil) {
     anObject = [[CustomObject alloc] init];
    }
    return self;
}

In Interface Builder I have the "value" of a text field bound to "anObject.textValue".

When I call this method:

[anObject setValue:@"Changed anObject.textValue!" forKey:@"textValue"];

then the text field updates to reflect the new value.

But what I want to do is display the values from an object which is given after doing some work elsewhere in the application. So what I did was this:

- (void)setCustomObject:(CustomObject *)newObject {
    anObject = newObject;
}

Now the result of this operation seems to break the bindings from the GUI to the CustomObject instance (anObject) which seems logical considering the bound object has been replaced by another instance.

What I want to know is if there is a way to keep the bindings functional with the dynamically created instance of CustomObject without having to re-bind every control programmatically through bind:toObject:forKeyPath:options: or similar which would require (to my knowledge) the use of IBOutlets to get a hold of the controls to then be able to bind them to the values in my new object (IMO this would make the bindings kind of useless in my situation). Is this the only solution or is there a better, cleaner way to deal with this?

I have read a good bunch of documents on developper.apple.com and elsewhere regarding bindings but I did not find anything which seems to talk about this particular case.

Thanks in advance for your time!

+1  A: 

Have a look at these docs on Key Value observing. This should show you how to change properties in a KVO compliant way.

Alternatively, set up anObject as a property:

@interface AppDelegate : NSObject {
    CustomObject *anObject; // This object has a "NSString *textValue" property
}
@property (retain) CustomObject *anObject;
...
@end

@interface AppDelegate
@synthesize anObject;

...
@end

Then when changing the anObject instance, use property syntax.

self.anObject = newObject;

This will take care of the KVO stuff for you.

note: Unless you have GC turned on your setCustomObject: method leaks.

Abizern
I do have GC turned ON and I did not include the memory management to keep the code as simple as possible for the question. Thanks for your answer! I'm going to try that tomorrow.
Form
Unfortunately I can't use Objective-C 2.0 because I'm working on Tiger. But the @property @synthesize is a good tip, I'll take note of this!
Form
+3  A: 

To be specific, I think the problem was that your setter method was called -setCustomObject: instead of -setAnObject:. If you made just that change I think that KVO would be invoked, and your bound textfields would be updated.

Abizern's note about it leaking (if you're not using GC) still applies though. Your setter should instead look something like:

- (void)setAnObject:(CustomObject *)newObject {
    if (anObject != newObject) {
        [anObject release];
        anObject = [newObject retain];
    }
}
Kelan
To clarify the problem further: The getter and setter (and you do need both) must be named after the property. Your property is `customObject`, so your getter must be named `customObject` and your setter must be named `setCustomObject:`. A property with synthesized accessors, as Abizern suggested, would be a really easy way to make this happen.
Peter Hosey
I'm going to look into that too tomorrow, thanks for your answer! I didn't do much manual memory management to date (I used the Garbage Collector), so this example will help. I'll take note of this for future projects.
Form
+1 Good catch on the improperly named setter method.
Abizern
That worked! It seems so logical now that you mention it. Thanks for your time everyone!
Form