Skip navigation.
 
mlRe: Bindings and object-pointer keys
FROM : Ken Thomases
DATE : Mon Dec 31 09:18:06 2007

On Dec 30, 2007, at 10:40 AM, Seth Pellegrino wrote:

> In the main interface, there are two table views, both controlled 
> by instances of NSArrayController. One shows employees, the other 
> displays jobs. The employees table view has three columns, name 
> (bound to arrangedObjects.name), title (arrangedObjects.job.title), 
> and salary (arrangedObjects.job). The salary column uses a custom 
> 'SalaryCell' which extracts a job's salary from a Job instance 
> (hence the unusual binding). In some "future version," this will be 
> necessary so the SalaryCell can draw itself differently to indicate 
> different jobs.
>
> Phew, time to discuss the actual problem. Simply put, changes made 
> to salaries in the job table are not reflected in the employees 
> table without a forced refresh. To see this, simply create ('Hire') 
> a person, use the pop up menu to set their job, and then try to 
> change their salary. The salary column won't update until the next 
> time the employees table becomes key.
>
> The reason for this problem is also rather simple -- technically, 
> the person's job property (to which the 'salary' table column is 
> bound) doesn't change. It's still a pointer to the exact same 
> memory location. However, the object at the other end of that 
> pointer has changed. Is there some way to make the bindings 
> mechanism aware of that fact? The options I see are a) somehow 
> track that changes have been made to a job object and then 
> programmatically force the table to refresh, or b) just throw up my 
> hands and switch to using Core Data.
>
> Is there a more elegant solution I'm missing? Failing that, which 
> of the above options would you recommend?


There may be a more elegant or correct solution, but the following 
should work:

Create a "synthetic" property on the Job class, let's call it 
salaryData.  Use setKeys:triggerChangeNotificationsForDependentKey: 
to make the salaryData property dependent on the salary key (and any 
other keys/properties on which SalaryCell bases its display and 
behavior).  Then, bind your salary column to the salaryData property.

So, what should the salaryData getter return?  As a first pass, 
perhaps just 'self' -- the Job instance, itself.  In the future, 
though, you might want to return some value object (e.g. a 
dictionary) which really represents the inputs for the SalaryCell.

The theory here is that the SalaryCell doesn't really depend on the 
whole job nor its identity.  In all probability, in a real-world 
application, a Job will have many properties, some of them relevant 
to the appearance and behavior of a SalaryCell, but most not.  In 
that case, you really don't want the SalaryCell to update itself 
every time _any_ property of a Job is changed.  It should really be 
bound to the specific aspects of a Job which are really relevant. 
So, SalaryCell should not be bound to the job instance, but to the 
property(ies) which are really relevant.

Put another way, I think both the existence of SalaryCell and your 
struggles to get bindings to do what you want are hints that you need 
another class.  There should be a value-object class, perhaps Salary, 
which aggregates the data relevant to representing salaries.  Your 
description of SalaryCell makes it clear that a simple number isn't 
sufficient; otherwise, you'd just bind SalaryCell to 
arrangedObject.job.salary.  So, whatever is the thing which a 
SalaryCell really represents, that's the contents of a Salary object.

You might be thinking that a Salary object is what your Job object 
already was.  The difference is that a Job is an entity.  Its 
identity is significant, and multiple Person objects share Job 
objects.  A Salary is a value object.  So, maybe it will end up being 
the case that a Job is a thin shell around a Salary.  That's fine if 
that's what is needed.  That way, multiple Person objects may all 
refer to a single Job, but when the Job's Salary is changed, that's 
done in a proper KVO-conforming way (for example, using -[Job 
setSalary:]).

I hope that helps.

Cheers,
Ken

Related mailsAuthorDate
mlBindings and object-pointer keys Seth Pellegrino Dec 30, 17:40
mlRe: Bindings and object-pointer keys I. Savant Dec 30, 18:00
mlRe: Bindings and object-pointer keys Seth Pellegrino Dec 31, 00:49
mlRe: Bindings and object-pointer keys mmalc crawford Dec 31, 00:58
mlRe: Bindings and object-pointer keys Seth Pellegrino Dec 31, 05:23
mlRe: Bindings and object-pointer keys mmalc crawford Dec 31, 06:27
mlRe: Bindings and object-pointer keys Ken Thomases Dec 31, 09:18
mlRe: Bindings and object-pointer keys Seth Pellegrino Jan 4, 15:07