Search code examples
cocoaoopcappuccinoobjective-j

Managing inverse relationships without CoreData


This is a question for Objective-J/Cappuccino, but I added the cocoa tag since the frameworks are so similar.

One of the downsides of Cappuccino is that CoreData hasn't been ported over yet, so you have to make all your model objects manually.

In CoreData, your inverse relationships get managed automatically for you... if you add an object to a to-many relationship in another object, you can traverse the graph in both directions.

Without CoreData, is there any clean way to setup those inverse relationships automatically?

For a more concrete example, let's take the typical Department and Employees example. To use rails terminology, a Department object has-many Employees, and an Employee belongs-to a Department.

So our Department model has an NSMutableSet (or CPMutableSet ) "employees" that contains a set of Employees, and our Employee model has a variable "department" that points back to the Department model that owns it.

Is there an easy way to make it so that, when I add a new Employee model into the set, the inverse relationship (employee.department) automatically gets set? Or the reverse: If I set the department model of an employee, then it automatically gets added to that department's employee set?

Right know I'm making an object, "ValidatedModel" that all my models subclass, which adds a few methods that setup the inverse relationships, using KVO. But I'm afraid that I'm doing a lot of pointless work, and that there's already an easier way to do this.

Can someone put my concerns to rest?


Solution

  • I can't speak specifically to Objective-J, but the usual way of doing this without Core Data is to set the inverse relationship in the setter. So, using the employees/departments example, you would do something like this:

    - (void)setDepartment:(Department *)aDepartment {
        if (department == aDepartment)
            return;
    
        [department release];
        department = [aDepartment retain];
    
        [department addEmployee:self];
    }
    

    You need to make sure you don't update your instance variable if the new value already matches the existing value. If you didn't, setDepartment: would call addEmployee:, and addEmployee: would call setDepartment: in an infinite loop.

    Also, note that this is an open invitation for retain cycles. It depends on how your model is structured, but the object that "owns" the the other is the one that should retain it. So my example is maybe not the best, because it's probably more accurate to say that the department "owns" the employee.