iOS Prefix.pch best practices
Solution 1:
Ewww… don't put macros in a .pch file! A .pch file is, by definition, a project specific precompiled header. It really shouldn't be used beyond the context of the project and it really shouldn't contain anything but #include
s and #import
s.
If you have some macros and such that you want to share between headers, then stick 'em in a header file of their own — Common.h
or whatever — and #include
that at the beginning of the .pch.
Solution 2:
For modern iOS and OS X, people should be using Modules. This is enabled by default for new projects, and importing/inclusion is accomplished using @import
.
Modules allow the compiler to create an intermediate representation of the contents of a module (e.g. a framework's headers). Much like a PCH, this intermediate representation may be shared across multiple translations. But modules take this one step further because a module is not necessarily target specific, and their declarations need not be localized (to a *.pch
). This representation can save you a ton redundant compiler work.
Using modules, you do not need a PCH, and you probably should just do away with them entirely -- in favor of using @import
local to the dependency. In that case, a PCH is only saving you from typing inclusions local to dependencies (which IMO you should be doing anyway).
Now, if we look back to the original question: You should avoid filling your PCH with all sorts of random things; Macros, constants, #defines
, and all sorts of little libraries. Generally, you should omit what really is unnecessary to the majority of your source files. Putting all sorts of stuff in your PCH is just adding a bunch of weight and dependency. I see people put everything they link and more to in the PCH. In reality, auxiliary frameworks typically only need to be visible to a few translations in most cases. E.g. "Here is our StoreKit stuff - let's import StoreKit only where it must be visible. Specifically, these 3 translations". This keeps your build times down, and helps you keep track of your dependencies, so that you may reuse code more easily. So in an ObjC project, you would usually stop at Foundation. If there is a lot of UI, then you might consider adding UIKit or AppKit to your PCH. This is all assuming you want to optimize build times. One of the problems with large PCHs that include (nearly) everything is that removing unnecessary dependencies is very time consuming. Once your project's dependencies grow and your build times go up, you need to fight back by eliminating unnecessary dependencies in order to reduce your build times. Also, anything that changes often should generally be kept out of your PCH. A change requires a full rebuild. There are some options to share PCHs. If you use PCHs, do aim to support sharing.
As far as what I put in my PCH: I stopped using them for the vast majority of targets years ago. There just usually is not enough in common to qualify. Bear in mind, I write C++, ObjC, ObjC++ and C - the compiler emits one for each lang in your target. So enabling them often resulted in slower compile times and higher I/O. Ultimately, increasing dependency is not a good way to fight dependency in complex projects. Working with multiple languages/dialects, there are is much variation in the dependencies required for a given target. No, I would not advise that as optimal for every project, but that does give some perspective to dependency management in larger projects.
References
- http://clang.llvm.org/docs/Modules.html
- http://clang.llvm.org/docs/PCHInternals.html
Notes
- This question was originally asked a few years before Modules' introduction.
- Presently (Xcode 5.0), modules work for C and ObjC, but not C++.
Solution 3:
I agree with bbum. My take on the PCH file is that it should contain pretty much only #include
or #import
statements. So if you have a bunch of helpful, high-level macros, define them in something like Common.h
and #import
that file, as bbum suggested.
I usually go a step further and use the PCH file to #import
a file called XXCategories.h
(where XX
is the class naming prefix convention you use) that contains #import
s for all my UIKit and Foundation class categories: NSString+XXAdditions.h
, UIColor+XXAdditons.h
, etc.