Editing Attractions- Using a Delegate

In my last post, I talked about using a delegate when editing Attractions. The problem I was trying to solve is that the current design has too much coupling:

  • The detail view controller needs to know whether or not it’s editing a new attraction or an existing attraction
  • The detail view controller needs to know about the AttractionStore

Here’s how I went about doing it. First, I defined the protocol for delegates to follow (a protocol is like an interface in .NET languages):

 @protocol AttractionDetailViewDelegate <NSObject>
 - (void) save: (Attraction *)attraction;
 @optional
 - (void) cancel;
 @end

The AttractionDetailViewController uses the delegate. I added a simple property on the class for callers to set the delegate. Then I call it as follows:

- (IBAction)save:(id)sender
{
  //...
  [self.delegate save:self.attraction];
  //...
}

- (IBAction)cancel:(id)sender
{
  if ([self.delegate respondsToSelector:@selector(cancel:)]) {
      [self.delegate cancel];
  }
  //...
}

Note that the cancel method is marked as optional in the protocol. Honestly, I haven’t actually found a use for it yet (other than testing). Strict adherence to YAGNI (You Aren’t Gonna Need It) says I should leave it off, but it feels more elegant and balanced to leave it on. In any event, the AttractionDetailViewController must first check to see if the method exists before calling it. Dynamically typed languages can be fun!

How are these delegates defined? Well, there are two- one for creating new Attractions, and one for editing existing Attractions. Let’s start with creation, since this is easier:

@interface CreateNewAttractionDetailViewDelegate : NSObject <AttractionDetailViewDelegate>
@end

@implementation CreateNewAttractionDetailViewDelegate
- (void)save:(Attraction *)newAttraction
{
    [[AttractionStore defaultStore] addAttraction:newAttraction];
}
@end

After defining the CreateNewAttractionDetailViewDelegate class, we implement the single method. When we call save, we just add the new Attraction to our data store. Easy. The Edit delegate is slightly more complicated:

@interface EditExistingAttractionDetailViewDelegate : NSObject <AttractionDetailViewDelegate>
@property (nonatomic, retain) Attraction *existingAttraction;
@end

@implementation EditExistingAttractionDetailViewDelegate
@synthesize existingAttraction = _existingAttraction;

- (void)save:(Attraction *)newAttraction
{
    [[AttractionStore defaultStore] replaceAttraction:self.existingAttraction WithAttraction:newAttraction];
}

- (void)dealloc
{
    [_existingAttraction release];
    [super dealloc];
}
@end

When we create the delegate, we set the existingAttraction property to be the Attraction we are currently editing. Then, when the user saves, we replace that Attraction with the new one we are passed in. The property adds some complexity, as we have to implement dealloc to clear it up, but it’s still a simple class.

And, with that, the AttractionDetailViewController now longer needs to know any details about Attractions are stored. It doesn’t need to know if we are creating a new Attraction, or editing an existing one. The responsibility of the class is to display and edit an Attraction- period. Much more elegant, in my opinion.

So where am I overall? I can now create, edit, reorder, and delete Attractions. But when the program ends, that beautiful Attraction list simply disappears. My next major programming task will be to implement persistence for this list.

But before I do that, I’m going to take some time to clean up code, and run it through some memory analysis tools. I suspect there’s at least one small memory leak, and I want to see if there are more. Establishing a habit to run these tools early and often feels prudent. Adding persistence will add quite a bit of complexity, and I want to start with a clean slate.