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
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 mails | Author | Date |
|---|---|---|
| Seth Pellegrino | Dec 30, 17:40 | |
| I. Savant | Dec 30, 18:00 | |
| Seth Pellegrino | Dec 31, 00:49 | |
| mmalc crawford | Dec 31, 00:58 | |
| Seth Pellegrino | Dec 31, 05:23 | |
| mmalc crawford | Dec 31, 06:27 | |
| Ken Thomases | Dec 31, 09:18 | |
| Seth Pellegrino | Jan 4, 15:07 |






Cocoa mail archive

