views:

977

answers:

0

Below is the "work horse" piece of code that I've implemented in order to display a many-to-many relationship in CoreData.

My UI is on a screen called "Expense". This expense can be associated with many transactions. (Also, transactions can be associated with several expenses). The UI contains the currently selected expense, and a table displaying all transactions (with a search field etc). This table has a column with a checkbox which allows you to pick and choose which transactions are associated with this expense.

Fyi, the code works. There are no crashes, no unexpected data corruptions, no nothings.

However, I would like to get community review on the code to see what you think. If there are things that could be done more elegantly. For example whether it is possible to achieve this using only bindings.

Last bit: the table is populated using bindings and controller objects. Except for the transactions column which is unbound. The dataSource of the table is set as this class.

Without further ado, the code:

// transactionController is an IBOutlet NSArrayConroller
// expenseController is also an IBOutlet NSObjectConroller 

- (id)tableView:(NSTableView *)table
objectValueForTableColumn:(NSTableColumn *)column
      row:(NSInteger)rowIndex
{
  if( [[column identifier] isEqualToString:@"relationship"] )
  {
    NSManagedObject *transaction = [[transactionController arrangedObjects] objectAtIndex:rowIndex];
    NSSet *relationshipSet = [expenseController valueForKeyPath:@"selection.associatedTransactions"];

    return [NSNumber numberWithBool:[relationshipSet containsObject:transaction]];
  }

  return nil;
}

- (void)tableView:(NSTableView *)table
   setObjectValue:(id)object
   forTableColumn:(NSTableColumn *)column
        row:(NSInteger)rowIndex
{
  if( [[column identifier] isEqualToString:@"relationship"] )
  {
    NSManagedObject *transaction = [[transactionController arrangedObjects] objectAtIndex:rowIndex];
    NSSet *relationshipSet = [expenseController valueForKeyPath:@"selection.associatedTransactions"];

    if( [object boolValue] )
    {
      if( [relationshipSet containsObject:transaction] )
        return;

      relationshipSet = [relationshipSet setByAddingObject:transaction];
      [expenseController setValue:relationshipSet
        forKeyPath:@"selection.associatedTransactions"];

    }
    else
    {
      if( ![relationshipSet containsObject:transaction] )
        return;

      NSMutableSet* newSet = [NSMutableSet setWithSet:relationshipSet];
      [newSet removeObject:transaction];

      [expenseController setValue:[NSSet setWithSet:newSet]
        forKeyPath:@"selection.associatedTransactions"];
    }
  }  
}