How to (temporary) disable clang warnings in Xcode
Ok, it sounds stupid at first sight, because warnings and errors are for us: they help the developer’s life to find out where are the problematic parts of our code. In the other hand you might end up in situation when you would like to switch off this feature. To be honest, disable warnings can be very handy but you need to use it really carefully.
I always check Issue navigator after builds, and I tend to keep it clear. In that way it gives me prompt feedback about real code issues. With an empty Issue navigator after the build you can be almost be sure (unless you are using the technique in this article too much;)), that your code is “good enough” for the compiler, which is the first step of delivering clean code.
Recently I stumbled into 2 problems where I decided to switch of warnings:
1. When I override the default initializer.
2. When I create unit test, testing nil for a nonnull
parameter.
How it works?
The easiest way is to use #pragma
in your code. The official name: Controlling Diagnostics via Pragmas, and you can find more information about it here: http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas.
In simply terms we need 3 steps:
1. Save the initial state: #pragma clang diagnostic push
2. Disable the specific warning: #pragma clang diagnostic ignored "[Warning_specific_switch]"
.
3. Restore the initial state: #pragma clang diagnostic pop
The [Warning_specific_switch] can be found here, thanks to the NSHipster author, Mattt Thompson.
Case 1: Default initializer
Let’s just create a new class, and creating a custom default initializer, and as a good citizen, I have just added the NS_DESIGNATED_INITIALIZER macro:
@interface PMOPictureWithURL : NSObject - (instancetype)initWithPictureURL:(NSURL *)url NS_DESIGNATED_INITIALIZER; @end
If I do the implementation of this designated initializer:
#import "PMOPictureWithURL.h" @implementation PMOPictureWithURL - (instancetype)initWithPictureURL:(NSURL *)url { self = [super init]; return self; } @end
I will be rewarded with the following warning:
Method override for the designated initializer of the superclass ‘-init’ not found.
Ok, I want to be still a good citizen, so I override the init and I want to disallow to other developers to use the default init
. Therefore I implemented only an exception when somebody is trying to use it:
- (instancetype)init { @throw [NSException exceptionWithName:@"Not designated initializer" reason:@"Use [[PMOPictureWithURL alloc] initWithPictureURL:]" userInfo:nil]; return nil; }
It seems that warning message changed, but now I have the following:
Convenience initializer missing a ‘self’ call to another initializer
Based on the 3 steps warning handling above, my final solution is:
#import "PMOPictureWithURL.h" @implementation PMOPictureWithURL - (instancetype)initWithPictureURL:(NSURL *)url { self = [super init]; return self; } //Save the diagnostic state #pragma clang diagnostic push //Ignore -Wobjc-designated-initializers warnings #pragma clang diagnostic ignored "-Wobjc-designated-initializers" - (instancetype)init { @throw [NSException exceptionWithName:@"Not designated initializer" reason:@"Use [[PMOPictureWithURL alloc] initWithPictureURL:]" userInfo:nil]; return nil; } //Restore the disgnostic state #pragma clang diagnostic pop @end
The warning message finally disappeared.
Case 2: Unit testing with nonnull
My second case is due to using the nonnull
keyword. I would do a longer post about the nullable/nonnull topic later, rather then going into the details now.It is enough to know that if a parameter or a return type marked as nonnull
, then clang will warn about the nil
value assignment.
Let’s change the code above and you will see what I am talking about:
@interface PMOPictureWithURL : NSObject - (nonnull instancetype)initWithPictureURL:(nonnull NSURL *)url NS_DESIGNATED_INITIALIZER; @end
As you can see I added the keyword nonnull
before the type declaration. Anytime I am trying to pass nil
as the url
parameter, clang will warn be, since I explicitly defined that it can not be null. If I want to do a Unit test, to see if I my app crashes if I assign nil
to the url
variable, I would do the following:
- (void)testIfNilPassed { PMOPictureWithURL *pictureWithURL = [[PMOPictureWithURL alloc] initWithPictureURL:nil]; XCTAssertNil(pictureWithURL); }
Clang will be so nice, and gives me a warning:
Null passed to a callee which requires a non-null argument
And clang has right. This is what I want to see everywhere in the code, except in my unit tests, where (hopefully) I know what I want to do.
Eventually, after applying the 3 steps above, my solution is:
//Save the diagnostic state #pragma clang diagnostic push //Ignore -Wnonnull warnings #pragma clang diagnostic ignored "-Wnonnull" - (void)testIfNilPassed { PMOPictureWithURL *pictureWithURL = [[PMOPictureWithURL alloc] initWithPictureURL:nil]; XCTAssertNil(pictureWithURL); } //Restore the diagnostic state #pragma clang diagnostic pop
Conclusion
Warnings are good. They are the clear signal of doing something wrong in your code. In the other hand, sometimes you need to ignore those warnings by disabling them, but if you do so, please be aware: Do it wisely and never forget #pragma clang diagnostic pop
, to restore the default setting.