#pragma

Written by Mattt Thompson on

#pragma declarations are a mark of craftsmanship in Objective-C. Although originally used to make source code compatible between different compilers, the Xcode-savvy coder uses #pragma declarations to very different ends.

In this modern context, #pragma skirts the line between comment and code. As a preprocessor directive, #pragma evaluates at compile-time. But unlike other macros, such as #ifdef...#endif, the way #pragma is used will not change the runtime behavior of your application. Instead, #pragma declarations are used by Xcode to accomplish two primary tasks: organizing code and inhibiting compiler warnings.

In addition to the #pragma syntax, both GCC and Clang have added the C99 _Pragma operator.

Organizing Your Code

Code organization is a matter of hygiene. How you structure your code is a reflection on you and your work. A lack of convention and internal consistency indicates either carelessness or incompetence--and worse, makes a project difficult to maintain and collaborate on.

Good habits start with #pragma mark. Like so:

@implementation ViewController

- (id)init {
  ...
}

#pragma mark - UIViewController

- (void)viewDidLoad {
  ...
}

#pragma mark - IBAction

- (IBAction)cancel:(id)sender {
  ...
}

#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  ...
}

#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  ...
}

Use #pragma mark in your @implementation to divide code into logical sections. Not only do these sections make it easier to read through the code itself, but it also adds visual cues to the Xcode source navigator (#pragma mark declarations starting with a dash (-) are preceded with a horizontal divider).

Xcode Sections

If your class conforms to any @protocols, start by grouping all of the methods within each protocol together, and adding a #pragma mark header with the name of that protocol. Another good convention is to group subclassed methods according to their respective superclass. For example, an NSInputStream subclass should have a group marked NSInputStream, followed by a group marked NSStream. Things like IBAction outlets, or methods corresponding to target / action, notification, or KVO selectors probably deserve their own sections as well.

Your code should be clean enough to eat off of. So take the time to leave your .m files better than how you found them.

Inhibiting Warnings

#pragma mark is pretty mainstream. On the other hand, #pragma declarations to inhibit warnings from the compiler & static analyzer--now that's pretty fresh.

You know what's even more annoying than poorly-formatted code? Code that generates warnings. Especially 3rd-party code. There are few things as irksome as that one vendor library that takes forever to compile, and finishes with 200+ warnings. Even shipping code with 1 warning is in poor form.

Pro tip: Try setting the -Weverything flag and checking the "Treat Warnings as Errors" box your build settings. This turns on Hard Mode in Xcode.

But sometimes there's no avoiding compiler warnings. Deprecation notices and retain-cycle false positives are two common situations where this might happen. In those rare cases where you are absolutely certain that a particular compiler or static analyzer warning should be inhibited, #pragma comes to the rescue:

// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
    self.completionBlock = ^ {
        ...
    };
#pragma clang diagnostic pop

This code sample from AFNetworking (contributed by Peter Steinberger) is an example of an otherwise unavoidable warning from the static analyzer. Clang notices a strong reference to self within the block, and warns about a possible retain cycle. However, the super implementation of setCompletionBlock takes care of this by nil-ing out the strong reference after the completion block is finished.

Fortunately, Clang provides a convenient way to get around all of this. Using #pragma clang diagnostic push/pop, you can tell the compiler to ignore certain warnings, only for a particular section of code (the original diagnostic settings are restored with the final pop).

You can read more about the LLVM's use of #pragma in the Clang Compiler User's Manual.

Just don't use this as a way to sweep legitimate warnings under the rug--that will only come back to bite you later.


So there you go: two ways you can markedly improve your code using #pragma declarations.

Like the thrift store 8-track player you turned into that lamp in the foyer, #pragma remains a curious vestige of the past: Once the secret language of compilers, now re-purposed to better-communicate intent to other programmers. How delightfully vintage!