Cocoa Bindings: Binding to Many at the End of Many Relationships

Using the Employees-Departments example, I want to associate a column with "Departments.arrangedObjects.employees. @ Sum.hoursWorked", as shown below:

Employee entity

  • : "firstName", "lastName", "hoursWorked"
  • relationship: "departments"

Entity department

  • attributes: "name"
  • relationship: "employees"

I need a table that will display summary information about departments.

I bind the first column to my Departments array controller, builtObjects.name. I can have a column showing the number of employees in the department, linking to "builtObjects.employees. @Count"

However, I canโ€™t get the amount of hours that employees have recruited, as I assume I can by becoming attached to "builtObjects.employees. @ Sum.hoursWorked"

The error I get corresponds to the lines "[<_NSFaultingMutableSet 0x1acea0> addObserver: forKeyPath: options: context:] is not supported. Key path: @ sum.hoursWork"

I believe that this is due to the fact that it is impossible to attach to many many-to-many relationships. If so, how can I do what I want?

For an additional loan, say, each employee has another attribute โ€œraceโ€, I would also like to see the number of unique races in each department in my resume table.

Thanks in advance.

+3
source share
1 answer

I encountered the same errors as you. It seems that although you can get a set of employees and perform on it some set of aggregate operations by doing something like:

Department * dept =; NSSet * employees = dept.employees; NSNumber * sumOfHoursWorked = [employee valueForKeyPath: @ "@ sum.hoursWorked"];

There when you connect, there is a difference. Bindings are asked to follow a key path, rather than evaluate it once. Given what this looks like, sorta makes sense why you can't get attached to these key paths. Like. Varieties.

Now. As for the solution, what I usually do in such cases is to write a tiny little subclass of NSValueTransformer to do what I need and then connect it to IB. Thus, I write ten lines of code that I need, but I donโ€™t end up making a complete NSTableView data source due to the lack of a simple aggregate. In this case, you can do something like this:

// Declaration @interface MySumOfHoursWorkedTransformer : NSValueTransformer @end @interface MyNumberOfRacesTransformer : NSValueTransformer @end // Implementation @implementation MySumOfHoursWorkedTransformer + (Class)transformedValueClass { return [NSNumber class]; } // class of the "output" objects, as returned by transformedValue: + (BOOL)allowsReverseTransformation { return NO; } // flag indicating whether transformation is read-only or not - (id)transformedValue:(id)value // by default returns value { NSNumber* retVal = nil; if ([value isMemberOfClass: [Department class]]) { double hoursWorked = 0.0; for (Employee* employee in [value valueForKey: @"employees"]) { NSNumber* hoursWorkedNumber = employee.hoursWorked; hoursWorked += hoursWorkedNumber ? [hoursWorkedNumber doubleValue] : 0.0; } retVal = [NSNumber numberWithDouble: hoursWorked]; } return retVal; } @end @implementation MyNumberOfRacesTransformer + (Class)transformedValueClass { return [NSNumber class]; } // class of the "output" objects, as returned by transformedValue: + (BOOL)allowsReverseTransformation { return NO; } // flag indicating whether transformation is read-only or not - (id)transformedValue:(id)value // by default returns value { NSNumber* retVal = nil; if ([value isMemberOfClass: [Department class]]) { NSMutableSet* raceSet = [NSMutableSet set]; for (Employee* employee in [value valueForKey: @"employees"]) { id raceVal = employee.race; if (raceVal) [raceSet addObject: raceVal]; } retVal = [NSNumber numberWithUnsignedInteger: raceSet.count]; } return retVal; } @end 

Then just bind these TableColumns to ArrayController.arrangedObjects and connect the corresponding value transformer subsystem. Now you cannot edit these values, but what would it mean to change the aggregate value?

Hope this helps. I used this approach in conjunction, and he is sure that he will refuse the bindings.

+1
source

Source: https://habr.com/ru/post/1399030/


All Articles