Silencing Specific Build Warnings

In one of the online communities I participate in, another developer recently asked the question:

What’s a good way to suppress a “Class Foo does not conform to protocol FooProtocol”? It’s a proxy object that forwards all messages to another conforming protocol.

To set the stage, this developer was creating a proxy object that would masquerade as another type of object. They want this proxy to indicate that it conforms to a protocol, but they don’t want to actually implement that protocol conformance. The implementation would be handled by the object that is being proxied, and the proxy wrapper would simply forward the method invocations on to the underlying object.

In other words, this developer knows that in this instance it’s “safe” to indicate conformance to a protocol, but not actually implement the protocol methods.

However, Xcode does not know this.


@protocol FooProtocol 
- (void)bar;
@end

@interface FooProxy: NSProxy <FooProtocol>
@end

@implementation FooProxy
... // implementation which does NOT include -bar
@end

If you write this code, then Xcode will complain at compile-time that you’re missing methods, and it will offer to provide implementation stubs for you.

In our particular case, we don’t want that, and instead want the compiler to leave us alone.

Finding the corresponding compiler flag

Our first step is to figure out which compiler flag is causing this warning.

To do this, we’ll go to the “Report Navigator” (⌘9) and select our recent build. We’ll scroll down the list of compilation steps until we find the one that’s producing our warning:

Select the compilation step

Next, we’ll click that little “hamburger” button over on the right end of the selected line, which expands to show us the actual compiler invocation, along with the resulting output. Scroll down, and we’ll see the raw output of the compiler for this step:

Expand the log line

The output that we see is this:

.../EmptyFoundation.m:16:17: warning: class 'FooProxy' does not conform to protocol 'FooProtocol' [-Wprotocol]
@implementation FooProxy
                ^
.../EmptyFoundation.m:16:17: note: add stubs for missing protocol requirements
@implementation FooProxy
                ^
1 warning generated.

These lines are what Xcode parses to show in the UI. Lines printed during compilation that start with warning: because warnings, and lines that start with error: become build errors. This, incidentally, can be really handy when you’re writing your own “run script” build phases or using other tools at compile time.

The part we’re interested though is the last bit of the warning message: [-Wprotocol].

That -W prefix is a huge hint that this is what we want. Compiler flags for clang that start with -W are the ones that enable specific build warnings. For more information on Clang warnings, check out this part of the Clang User Manual.

Alternative Approaches

There are 3 main ways of suppressing a particular warning:

  1. Suppress it for an entire project

    This would involve going in to the build settings for your target (or project, or xcconfig file, etc), finding the corresponding setting, and changing its value. In our particular case, that would be this:

    Suppress warning via target build settings

    For our particular use-case, this is too broad of a change. We want to maintain this warning for other protocol implementations. So, we will not make this change.

  2. Suppress it for a particular file

    Alternatively, we could silence this warning for everything in a particular file. To do this, we would go to the “Build Phases” section of our target and expand the “Compile Sources” build phase. All the files compiled for this target are listed here, and for each file we have the option to add extra flags to be used when compiling that file.

    Following along with standard Clang flag syntax, we could add the -Wno-protocol flag for our file, to silence the build warning for our file:

    Suppress warning for a particular file

    This might be an appropriate change for our situation. However, I think we’d still want the other code in the file to stick with the default behavior, so we won’t use this option either.

  3. Suppress it for a specific block of code

    Instead, we’ll suppress this warning directly in our source file.

Suppressing warnings in code

Let’s head back to our code and take advantage of Xcode snippets.

We’ll position our cursor before our @interface declaration and type the word ignore. Xcode will offer to expand a “Clang Ignore Warning” macro:

Xcode ignore snippet

If we select this, we’ll get all the boilerplate that we need inserted:

Expanded Xcode ignore snippet

The warning-name in the snippet is where we type in the name of our warning (protocol), and the code placeholder is the block of code for which this warning will be suppressed.

If we fill in those values and rebuild, we’ll see we build without warnings nor errors:

Clean build

(Technically we only need the macros to surround the @implementation, as that is the part of the code where the compiler checks to make sure the protocol requirements are fulfilled)

Conclusion

There’s a lot of really neat information hiding inside Xcode, if you know where to look. You can find which compiler flags are producing warnings. You have multiple ways of suppressing them (if you’re sure that’s the correct way to solve the issue). You can produce your own build warnings and errors. And, you have Xcode snippets that can automatically stub out things for when so you don’t have to spend as much time searching the internet for arcane compiler diagnostic option macros.


Related️️ Posts️

Building a Cross-Platform Framework
Conditional Compilation in Swift, Part 2
Conditional Compilation in Swift, Part 1