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.


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.