Rapture In Venice, LLC

:: Freelance iOS Development & Team Augmentation

Pragmas Aren’t Just For Marks

Ask an iOS developer what a #pragma is and more times than not they’ll tell you, “It’s a directive that lets you group your functions in XCode’s method index thingy.” OK, I confess, that’s what my answer would’ve been not too long ago!

The truth is, there are plenty of #pragma usages out there and some of the more low-level minded developers use them quite a bit! In many cases, they can be abused and make reading source code a real downer, but let’s review some of the more useful ones and embiggen ourselves. :-)

NOTE: This blog will only refer to the Clang compiler (LLVM) and not GCC, though some of it still applies. Since I don’t see any reason to be using GCC anymore, I’m not going to explicitly talk about it.

Explicit warnings and errors

The compiler is a robot; it will mark what’s wrong with your code using a set of rules that’ve been defined by Clang. But, every so often you’re smarter than it. Often, you might find some offending code that you know will lead to problems but, for whatever reason, can’t fix yourself at the moment. You can explicitly signal errors like this:

- (NSInteger)divide:(NSInteger)dividend by:(NSInteger)divisor {
    #error Whoa, buddy, you need to check for zero here!
    return (dividend / divisor);
}

You can signal warnings similarly:

- (float)divide:(float)dividend by:(float)divisor {
    #warning Dude, don't compare floating point numbers like this!
    if (divisor != 0.0) {
        return (dividend / divisor);
    } else {
        return NAN;
    }
}

These warnings and errors will show up in XCode’s Issue Navigator like any other warning and error:


The alternative is running a git blame and emailing the developer, but it might take too much time and it’s nicer to signal the issue right where the code is. I’ve even seen developers mark these warnings when writing their own code as a reminded to change the code later. Use it however it’s most useful to you and your team.

Oh, and strictly speaking, this isn’t a #pragma, but it’s in the same family and #pragma message behaves the same way as #warning.

Temporarily disable a compiler behavior

While most iOS developers don’t futz around much with compiler options, it’s these options which control how strictly to check (or not check) your code for errors. Sometimes, though, you want to make an exception…just once. The best way to do this to put your offending code on an island with no law.

Here’s something I ran into with InnerBand: When you use ARC, the compiler inserts memory-management calls for you. There are cases, though, where it can get confused. One such case is when you use NSSelectorFromString to have a dynamically-named selector called. Since ARC can’t know what the method will be and what kind of memory management to use, you’ll be warned with something like, “performSelector may cause a leak because its selector is unknown”.

If you know your code won’t leak, you can suppress the warning for just this instance by wrapping it like this:

    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                            
    [myObj performSelector:mySelector withObject:name];
    
    #pragma clang diagnostic pop						

Note how we disable the -Warc-performSelector-leaks check by pushing and popping the change around our code. This assures us we don’t disable it globally, which would be a huge mistake.

There’s a large number of options you can disable if need be, but you’ll have to consult The Clang User’s Manual to learn about all of them.

Suppressing warnings for unused variables

It’s useful to be told that a variable you’ve defined is going unused. In most cases, you want to remove these references to improve performance (however slightly), but sometimes you want to keep them. Why? Perhaps they have a future usage or the functionality is only temporarily removed. Either way, you can suppress the warning with #pragma unused:

- (void)giveMeFive {
    NSString *foo;
    #pragma unused (foo)

    return 5;
}

Now you can keep your code in place without the compiler complaining about it. And yes, that pragma needs to go below the offending code.

Conclusion

Pragma are there to help you, but don’t abuse them. Looking at code loaded up with preprocessing code and pragmas is like reading code with gotos, a total headache. Use them appropriately!

  • Print
  • Facebook
  • Twitter

John Blanco

John Blanco is a freelance iOS developer living in Lakewood, Colorado. He's been developing mobile apps for over 15 years, beginning in the medieval days of Java ME and Blackberry and all the way through iPhone and Android! He's led development on dozens of apps across a wide variety of domains such as retail, vision, orthotics, games, sports, and more!

More Posts - Website

Follow Me:
LinkedIn

Comments are currently closed.