In Objective-C, there are subtle issues around #import order. You may not believe me—until you try reusing code in a new project.
In Wild #imports! we looked at the problems caused by having too many #import directives. But it’s also possible that you have too few, resulting in bad header files—especially if you don’t pay attention to #import order in your .m files.
Improve your test writing “Flow.”
Sign up to get my test-oriented code snippets.
Make Imports Minimal and Complete
When it comes to imports, header files should satisfy these two conditions:
- They should be minimal
- They should be complete
“Minimal” just means a header file should import no more than it needs.
“Complete” means the header file imports everything that needed to compile it. Consider:
#import "foo.h" #import "bar.h"
If removing foo.h (or changing the order) causes bar.h not to compile, then bar.h is not complete.
Uncover Incomplete Headers
One way to have an incomplete header is by relying on precompiled headers. In particular, just because the precompiled headers include a particular header doesn’t mean you can omit it elsewhere.
Another way to have an incomplete header is with a poor #import order that masks dependencies. In C-based languages, programmers often begin their implementation files by including the most general headers from the largest scope. They work down from there, until they reach the most specific headers:
- system headers
- other headers
- finally, the unit’s own header
This is backwards. Consider a header foo.h that depends on <QuartzCore/QuartzCore.h>. If foo.m imports QuartzCore first, then other stuff, then finally gets to its own header, you may not feel the need to import QuartzCore in foo.h. …And this will break for the next programmer who comes along and just imports foo.h.
In Objective-C, poor #import order masks dependencies
Good #import Order
Disclosure: The book links below are affiliate links. If you buy anything, I earn a commission, at no extra cost to you.
The solution is simple: reverse the order! Start from the most specific, then work towards the most general. Most importantly, include your own header first. Large-Scale C++ Software Design by John Lakos is the only book I know about “physical design”—how to arrange source code into files.
The author states,
Latent usage errors can be avoided by ensuring that the .h file of a component parses by itself—without externally-provided declarations or definitions… Including the .h file as the very first line of the .c file ensures that no critical piece of information intrinsic to the physical interface of the component is missing from the .h file (or, if there is, that you will find out about it as soon as you try to compile the .c file).
In other words, by including your own header first… if the header is not complete, you will fail fast!
Here’s what I do. If I’m writing foo.m, I first import foo.h. I keep this separated from other imports by a blank line. All the others follow, in sorted order:
#import "foo.h" #import "abc.h" #import "def.h" #import <Abc/Abc.h>
Sorting helps me find duplicates. It also puts angle brackets imports <> after quoted imports, so that the most general headers come last.
Questions: What ordering do you use for your #import statements? What tools do you use to help with your ordering? Leave a comment below.
One of the things I like about AppCode is its ability to organise imports, automatically removing unused imports or adding them when you refer to new symbols while writing. That’s great for TDD as it means you can focus on what you want to say and let the IDE handle the ceremony needed by the compiler.
On the other hand, it considers imports that are already included in the project’s PCH to be redundant and will remove those. Using the same rules you outline above, this is not a good thing.
Yup. But since my precompiled headers contain only angle-bracket-style imports, and AppCode visually distinguishes those headers it thinks are redundant, I can choose to apply AppCode’s rules only to quote-style imports. Then once in a while, I do a sweep: I temporarily set my prefix not to include any headers, and let AppCode do its thing. That’s been a timesaver on big legacy projects with messy imports.
Hi Jon, stumbled upon your post while surfing. Interesting post. One question about the “specific to general” ordering of header (#imported of course) though.
Support by accident there are two #define, the first occurrence in the local (now ordered first) header which is the one the programmer wants, and the other in a framework (now ordered latter) header. Wouldn’t the preprocessor pick the definition defined in the framework instead of what the programmer wants?
As a side note, this scenario does justify your other post (https://qualitycoding.org/preprocessor/) about #define which I agree 100% with.
Chris, if you have a project containing two different files but sharing the same name, you have other problems! Thankfully, the problems should be obvious if it doesn’t even compile.
Thanks for the article, Jon! It exactly matches the way I organize the imports, and my reasoning is the same. The only exclusion is for the empty line after the first #import “foo.h” :-)
I’d just wanted to add that in my case I use quite a few (own) frameworks, and there’re inter-framework dependencies. So, imports for most specific frameworks go first, then imports for less specific frameworks and etc.
Btw, what I like about imports, is that when used properly, they reveal/show the real dependencies, so it allows to estimate the complexity of the source that uses them.
Last thing: you can make an simple automator action with “sort | uniq” for sorting selected imports in Xcode.
Yes, revealing the dependencies is a benefit to cleaning up imports. I like to use https://github.com/nst/objc_dep to visualize the dependency graph.
Thank you for writing this post. I am still pretty new to iOS development, and seeing tips like this helps me get started with the best food forward. I do occasionally program in C though, so this will also be helpful there.
I just have one small question. Is there any functional reason for splitting the unit’s own header from the other imports with the blank line? I would guess it is just to demarcated the difference between it and the “other headers”, since they look identical (while the system ones are obviously different due to the ). Is that why? Or is it just style, like curly-braces inline or on the next line from an if-statement?
Nick, I like to keep the “own header” separate to emphasize its position, especially when other programmers are involved who may not know why it comes first.
Hey Jon, sorry if this is a dumb question, but I don’t fully see why the ordering of the .m affects the .h file. If I need QuartzCore in my .h and I import it first in my .m, won’t my .h still complain about not knowing what the needed classes from QuartzCore are?
It seems like Xcode will tell me if my .h is complete regardless of what I import in my .m?
Luke, #import is a preprocessor directive. It’s effectively the same as copying and pasting. So if you import QuartzCore first, and your “self” header last, it all expands in your .m before it’s compiled. That’s why the ordering matters.
Did that make sense?
Hopefully this will gradually become history with modules and @import.
So if you import QuartzCore at the end will it not expand in your m?
It will. But if it’s expanded before other headers that use it, those headers will pick it up by accident, not by design. By importing it at the end, any headers that need it but don’t import it themselves will cause a compile-time error. Which is what I want. I want the compiler to tell me about headers that don’t declare their dependencies.
Ah, ok got it, thanks!