objective-cdelegationios-3.x

Data provider calling a delegate: specifics or generic?


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?


Solution

  • First method:

    Pros:

    Cons:

    Second method:

    Pros:

    Cons:

    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).