I know there’s no one answer to this question, but I’d like to get people’s thoughts on how they would approach the situation.
I’m writing an Objective-C wrapper to a C library. My goals are:
1) The wrapper use Objective-C objects. For example, if the C API defines a parameter such as char *name, the Objective-C API should use name:(NSString *).
2) The client using the Objective-C wrapper should not have to have knowledge of the inner-workings of the C library.
Speed is not really any issue.
That’s all easy with simple parameters. It’s certainly no problem to take in an NSString and convert it to a C string to pass it to the C library.
My indecision comes in when complex structures are involved.
Let’s say you have:
struct flow
{
long direction;
long speed;
long disruption;
long start;
long stop;
} flow_t;
And then your C API call is:
void setFlows(flow_t inFlows[4]);
So, some of the choices are:
1) expose the flow_t structure to the client and have the Objective-C API take an array of those structures
2) build an NSArray of four NSDictionaries containing the properties and pass that as a parameter
3) create an NSArray of four “Flow” objects containing the structure’s properties and pass that as a parameter
My analysis of the approaches:
Approach 1: Easiest. However, it doesn’t meet the design goals
Approach 2: For some reason, this seems to me to be the most “Objective-C” way of doing it. However, each element of the NSDictionary would have to be wrapped in an NSNumber. Now it seems like we’re doing an awful lot just to pass the equivalent of a struct.
Approach 3: Seems the cleanest to me from an object-oriented standpoint and the extra encapsulation could come in handy later. However, like #2, it now seems like we’re doing an awful lot (creating an array, creating and initializing objects) just to pass a struct.
So, the question is, how would you approach this situation? Are there other choices I’m not considering? Are there additional advantages or disadvantages to the approaches I’ve presented that I’m not considering?
I think that approach 3 would be the preferred way to do things. When you wrap a library you’ll want to create wrappers around any object or structure that the user is expected to deal with.
If you wrap everything, then you are free to change the internal workings of your classes at a later date without affecting the interfaces that your users have become accustomed to. For example, in the future you may realize that you’d like to add some type of error checking or correction… maybe setting a
stopthat is earlier than thestartcauses some calculation errors, you could change thestopmethod in your Flow wrapper to setstartequal tostopifstopis less thanstart(I admit, that’s a really bad example).