Welcome to Brian Webster's Blog

Typedef Objective-C generics to clear up visual clutter

 | 

I’m working on a rather large Objective-C codebase, so I haven’t been able to do a ton of Swift yet, but I have been starting to try to take advantage of the new nullability and generics capabilities that have been added to Objective-C. Even though my code doesn’t interact with much Swift code yet, you do get some benefits even in a pure ObjC codebase.

One of the downsides to Objective-C generics though is that your type declarations get really big and hard to read. For example, in the code I was just working on, I wanted to have a dictionary that mapped from one set of NSURLs onto another set of NSURLs. In Swift, the type would simply be declared [NSURL:NSURL] but in Objective-C, you get the much less clean NSDictionary<NSURL*, NSURL*>* Once you start declaring this in multiple places, passing parameters, etc. it can make your code very hard to read. One brief example:

- (NSDictionary<NSURL*, NSURL*>*)mapSourceURLs:(NSArray<NSURL*>*)sourceURLs toContentsOfDirectory:(NSURL*)directoryURL
{
    NSDictionary<NSURL*, NSURL*>* urlMap;
    //code code code...
    return urlMap;
}

After briefly contemplating rewriting the whole class I was working on in Swift just so I could minimize the offense to my delicate eyes, I remembered that C has a tool to help with this kind of thing, trusty old typedef! I started by declaring the following at the top of my source file:

typedef NSDictionary<NSURL*, NSURL*>* IPURLMap;

Then, I changed my variable declaration in my method to the following:

IPURLMap* urlMap;

However, this brought up a compiler error stating: pointer to non-const type 'IPURLMap' (aka 'NSDictionary *') with no explicit ownership. This was because I had declared the IPURLMap type as a pointer to a dictionary, but then the variable declaration was also declared as a pointer, which threw off the compiler. I could remove the asterisk from the variable declaration, but that looked weird to me, since it doesn’t look like I’m declaring an Objective-C object there. So instead, I removed the asterisk from the typedef, so it ended up like so:

typedef NSDictionary<NSURL*, NSURL*> IPURLMap;

With that, the method declaration now becomes:

- (IPURLMap*)mapSourceURLs:(NSArray<NSURL*>*)sourceURLs toContentsOfDirectory:(NSURL*)directoryURL
{
    IPURLMap* urlMap;
    //code code code...
    return urlMap;
}

Even though the typedef itself looks a little weird without the asterisk there, the method is much cleaner and easier to read, so I find this to be a big improvement. I could do something similar for the NSArray<NSURL*>* parameter in the method as well, and so forth. I hope others find this as useful as I have, and feel free to chime in if you have any other suggestions or improvements.