As our codebase matures I'm starting to not like the pattern of passing dictionaries as a way to package up information for message passing or, worse yet, function arguments. It necessitates the sending and receiving function both having an undocumented API of string literals.
..in some function..
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
thisObject, @"thisKey",
thatObject, @"thatKey",
nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"MY_NOTIFICATION" object:nil userInfo:info];
....
and then in someClass
's listener
- (void)someClassListener:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
ThisObject *ob1 = [info objectForKey:@"thisKey"];
ThatObject *ob2 = [info objectForKey:@"thatKey"];
}
You have to remember that thisKey
and thatKey
are the keys of type ThisObject
and ThatObject
for that notification, sure you could create some constants somewhere for those keys but that doesn't really solve the problem.
And lets say you have a function that needs 15 arguments, you're not going to make a function with 15 parameters, it'd be much easier (though less readable) to just pass a dictionary but now you have the same problem as above.
I played with creating stubbed out 'Message Classes' in those class' header files (ie two interfaces in one header) and the Message Class was just a list of objects that you define and send to the method which creates a stronger contract but this feels Wrong.
It'd be great if I could do something like typeDef
a parameter object in the header but that doesn't support NSObject
's only things like int
or float
etc.
Essentially I'm trying to create a stronger contract between the message sender and message receiver, be that functions or notifications.
You could define constants for the keys. As an example, see the docs for UIKeyboardDidShowNotification
for an example. There is a link to all of the keys that can be used to get info about the notification.
A better approach would be to encapsulate your data into a class instead of a dictionary. Create a simple class with properties. This will be much more self documenting than a dictionary. You can see the property names and the property types in the .h file.
If you find you have methods needing 15 arguments, you need to step back and encapsulate those arguments into an appropriate class. Perhaps the method properly reduces to a couple of arguments and a class or something similar.
What you want is a parameter object, a small object that encapsulates a bunch of fields for convenient communication with some other class. Internally, the parameter object might hold a dictionary, or simply a set of designated fields.
Give the parameter object a simple API that lets both classes set and get the specific fields you use -- setThisKey: and getThisKey. That, in essence, documents the API between the methods and classes.
Next, look for opportunities to move functionality into the parameter object. For example, if you have something like this:
param.fieldSize=[self.data size];
param.fieldColor=[self.data color];
param.flavor=[self.data lookUpTheRecipe]
You could encapsulate all this with
[param withField: self.data];
With work, you can often make the parameter object do lots of useful work; this can break up long methods and help big classes shed excess responsibilities.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With