views:

265

answers:

4

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?

+2  A: 

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.

Alex
Thanks, that's basically what I'm doing. (Excepting using KVO to trigger when either side changes, and adding the other.)So it looks like I'm on the right track, thanks.
Nathaniel Martin
If that's what you're doing, you are on the right track. I think my approach _may_ be a little easier just because of the overhead of doing KVO, but either way should work fine.
Alex
The main reason I'm using KVO is so that I don't have the modify the generated accessors.Instead, in my init method I call a method that describes the type of relationship, what property to use, and what the inverse relationship property is. This automatically sets up the observers, etc.I'll share the code after I've got it all working.
Nathaniel Martin
+2  A: 

You probably want to set the relationship in your setter. Using your example the Objective-J code would look similar to this.

- (void)setDepartment:(Department)aDepartment {
    if (department === aDepartment)
        return;

    [department addEmployee:self];
}

As you can see there is no need for retain / release. Objective-J is built upon javascript which is garbage collected. All the memory management methods are implemented but do nothing (apart from cluttering your code)

Also because this is javascript it's generally advisable to check for type equality (===) For more information on type equality see: http://www.webreference.com/js/column26/stricteq.html

klaaspieter
Yeah, not having to worry about retain / release is nice.I'll keep in mind the type equality, thanks!
Nathaniel Martin
+2  A: 

Hey Nathaniel,

check out the Cappuccino Extensions from this 280 North employee: http://github.com/nciagra/Cappuccino-Extensions

It includes an ActiveRecord port. I haven't actually looked at any of this up close yet, but it might help you.

  • Johannes
Johannes Fahrenkrug
That looks very cool, I'm going to have to explore that more. Unless I'm mistaken though, I think it takes care of most of the validation, etc on the server side. That's important to do of course, but I think doing client-side validation is important as well, to give a fast experience to the user.
Nathaniel Martin
+1  A: 

You can also check out this implementation of CoreData by rbartolome. I've only looked at it a little bit, but it looks like a start.

http://github.com/rbartolome/CoreData-Cappuccino

Jeff Camozzi