In one of the online communities I participate in, another developer recently asked the question:
What’s a good way to suppress a “Class
Foodoes 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:
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:
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:
-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.
There are 3 main ways of suppressing a particular warning:
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:
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.
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-protocolflag for our file, to silence the build warning for our 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.
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:
If we select this, we’ll get all the boilerplate that we need inserted:
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:
(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)
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.