3

I have a XML parser which will parse 17 different XML documents (I'm simplifying this). When the parser has finished its job, it calls the object that did the request.

First way

A single method that looks like

- (void)didReceiveObject:(NSObject *)object ofType:(MyObjectType)type

with MyObjectType being an enum.

In this method, I check the type and redirect the object to the corresponding method.

Second way

There is a callback method for each of the 17 types of object I can receive.

- (void)didReceiveFoo:(MYFoo *)foo
- (void)didReceiveBar:(MYBar *)bar
... and so on

Which way of using delegates will be better? We had a discussion about this with a colleague and couldn't find one way more appealing than another. It seems like it's just deciding what method to call from the parser or within the delegate....

Even when thinking about adding future methods/delegates callbacks, we don't see any real problem.

Is one of these ways better than the other? Is there another way?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
teriiehina
  • 4,741
  • 3
  • 41
  • 63

3 Answers3

2

Why not go with

- (void)didReceiveObject:(NSObject *)object

and then inspect the class type?

This seems cleaner and more extensible to me, because it means you can parse other objects in the future without adding more callbacks.

(I know this is the same as option one, but I wanted to point out that your second argument was unnecessary.)

Evan Cordell
  • 4,108
  • 2
  • 31
  • 47
  • I second this. The main benefit here is that if there's any common work between the different types, you can collect it in one place and keep DRY. – Morgan Harris Aug 03 '11 at 07:02
  • I'm not sure that is the same because using an enum tells you all the classes you may receive. If we were to used this way, we will have to specify somewhere else which classes you should test. the main point is: we want to give the information about the type of the object: should we specify it in the method's name or in its parameters. – teriiehina Aug 03 '11 at 10:42
1

First method:

Pros:

  • More flexible to future changes.

Cons:

  • May result in a large switch statement or messy if ... else if ... else statement.
  • Probably results in a series of explicit methods anyway.
  • Requires type cast.

Second method:

Pros:

  • No type casting.
  • If methods are optional, delegate is only bothered with the objects it's interested in.

Cons:

  • If methods are not optional and the interface is expanded later, all delegates will have warnings until the new methods are implemented.
  • If methods are not optional, this can be a lot of methods to implement for every delegate.

Generally when building delegate interfaces I lean towards generics for future extensibility. Changing an API, especially with open source code, can be very difficult. Also, I don't quite understand why you have one XML parser doing so much. You may want to consider a different design. 17 different XML documents seems like a lot. That aside, I'll propose a third method.

Third method:

Create a dictionary that maps strings to blocks. The blocks would probably be of type void(^BlockName)(id obj). Your parser would define a series of strings that will be the keys for your various blocks. For example,

NSString * const kFooKey = @"FooKey"; 
NSString * const kBarKey = @"BarKey";
// And so on...

Whoever creates the XML parser would register a block for each key they are interested in. They only need to register for the keys they are interested in and it's completely flexible to future change. Since you are registering for explicit keys/objects, you can assert the passed in type without a type cast (essentially Design By Contract). This might be over kill for what you want, but I've found similar designs very beneficial in my code. It combines the pros of both of your solutions. It's main downfall is if you want to use an SDK that doesn't have blocks. However, blocks are becoming a de facto standard with Objective-C.

On top of this you may want to define a protocol that encompasses the common functionality of your 17 objects, if you haven't done so already. This would change your block type to void(^BlockName)(id<YourProtocol> obj).

rbrown
  • 2,635
  • 2
  • 24
  • 24
  • I really like your idea. I'm sorry I didn't specify that we have to stick with iOS3. I'll check again with we can go iOS4+ only but last time was a no. – teriiehina Aug 03 '11 at 10:45
0

Here's the decision.

We will implement both and see which way is the more used.

The first way is the easiest and fastest so we will keep it for internal needs.

But we may be shipping this code as a static library so we want to give the minimal amount of information. So we will also stick with the with the second way.

As there should be a big chunk of code for each callback, the generic way will certainly be the big switch statement rbrown pointed.

Thank you for your help.

teriiehina
  • 4,741
  • 3
  • 41
  • 63