title | author | category | tags | excerpt | status | ||
---|---|---|---|---|---|---|---|
#pragma |
Mattt Thompson |
Objective-C |
nshipster |
`#pragma` declarations are a mark of craftsmanship in Objective-C. Although originally purposed for compiling source code across many different compilers, the modern Xcode-savvy programmer uses #pragma declarations to very different ends. |
|
#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.
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]({{ site.asseturl }}/pragma-xcode-sections.png)
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.
#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!