I’ve started turning on most of Xcode’s warning options and one warning-related build setting in all of my personal projects. I suggest you do the same.

The easiest way to do this nowadays is to use this xcconfig file, which turns all of the settings described here on at once.

There are some warnings I don’t turn on, for any of several reasons:

The rest of the warnings, I turn on because either they make something clearer or they tell me about either real or potential (i.e., future real) bugs. They are:

Check Switch Statements Warn whenever a switch statement has an index of enumeral type and lacks a case for one or more of the named codes of that enumeration. The presence of a default label prevents this warning. Leave no case unhandled. Consider whether a default: label is appropriate for your enumeration. If your switch statement handles all possible values, cut out the default and assert that the value is one of the possible ones instead. An easy way to do this, if the enumeration values are serial and the enumeration is not part of an API you expose, is to have one extra name defined as the number of possible values: enum Foo { kFooFoo, kFooBar, kFooBaz, kFooNumberOfValidFooValues }; Then, in your assertion macro, compare the value against that name: #define MyParameterAssertValidFoo(foo) \ NSAssert1((foo) < kFooNumberOfValidFooValues, @"Invalid Foo value: %d", (foo)); When you add kFooQux , insert it above kFooNumberOfValidFooValues , and the value of kFooNumberOfValidFooValues will increase by one to fit it. The result is that your switch statement covers all known values for the enumeration (or you get a warning because it doesn't), and your method throws an exception (from the assertion) whenever anyone passes an unknown value.

Hidden Local Variables Warn whenever a local variable shadows another local variable, parameter or global variable or whenever a built-in function is shadowed. One common way to get this warning is to name a variable index , because there is a function by that name in the standard C library. That's not as much of a false positive as you may think: If you fail to declare your index variable, all your references to it will actually refer to the index function. You can see how it would be bad to send a message such as [myArray objectAtIndex:index] with this bug. The solution is simple: Never, ever name a variable index .

Implicit Conversion to 32 Bit Type Warn if a value is implicitly converted from a 64 bit type to a 32 bit type. This is most useful when converting old code to work correctly in a 64-bit architecture. Storing a pointer into an int variable (such as a reference constant) when targeting an LP64 architecture is a good way to get this warning, and rightly so.

Initializer Not Fully Bracketed Example, Here initializer for a is not fully bracketed, but that for b is fully bracketed. int a[2][2] = { 0, 1, 2, 3 }; int b[2][2] = { { 0, 1 }, { 2, 3 } }; This is a cleanliness warning. It also applies to structures, such as NSRect : NSRect warns = { 0.0f, 0.0f, 640.0f, 480.0f }; NSRect doesNotWarn = { { 0.0f, 0.0f }, { 640.0f, 480.0f } }; (In real code, I'm more likely to use NSZeroPoint instead of the { 0.0f, 0.0f } element above. It's harder to spell that wrong and get away with it than it is to get away with typing 9.9f , 1.1f , or 2.2f instead of 0.0f .)

Mismatched Return Type Causes warnings to be emitted when a function with a defined return type (not void ) contains a return statement without a return-value. Also emits a warning when a function is defined without specifying a return type.

Missing Braces and Parentheses Warn if parentheses are omitted in certain contexts, such as when there is an assignment in a context where a truth value is expected, or when operators are nested whose precedence people often get confused about. Also warn about constructions where there may be confusion to which if statement an else branch belongs. Here is an example of such a case: if (a) if (b) foo (); else bar (); In C, every else branch belongs to the innermost possible if statement, which in this example is if (b) . This is often not what the programmer expected, as illustrated in the above example by indentation the programmer chose. This may appear to be just a cleanliness warning, but as you can see from the example, it can also warn you about code that may not flow the way you expect it to.

Missing Fields in Structure Initializers Warn if a structure's initializer has some fields missing. For example, the following code would cause such a warning, because " x.h " is implicitly zero: struct s { int f, g, h; }; struct s x = { 3, 4 }; This option does not warn about designated initializers, so the following modification would not trigger a warning: struct s { int f, g, h; }; struct s x = { .f = 3, .g = 4 }; I'm not sure why it warns about the former and not the latter, since all the members get initialized in both code examples (C99 §6.7.8 ¶21). If nothing else, this warning is good motivation for you to switch to designated initializers, which make your code more explicit about which members it's initializing.

Missing Newline At End Of File Another cleanliness warning—this one, about the cleanliness of diffs.

Sign Comparison Warn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned.

Strict Selector Matching Warn if multiple methods with differing argument and/or return types are found for a given selector when attempting to send a message using this selector to a receiver of type " id " or " Class ". When this setting is disabled, the compiler will omit such warnings if any differences found are confined to types which share the same size and alignment. I don't turn this one on, because it's unnecessary. When the multiple declarations differ significantly (e.g., one method returns an object and the other returns a float ), the compiler will raise the warning whether it's turned on or not. When the declarations don't differ significantly (e.g., both methods return an object), the difference won't cause a problem, so you don't need to worry about it. So, you should leave this one off.

Typecheck Calls to printf / scanf Check calls to printf and scanf , etc, to make sure that the arguments supplied have types appropriate to the format string specified, and that the conversions specified in the format string make sense. The biggest reason to turn this on is that it checks your use of methods that take a nil -terminated list of arguments: NSArray *array = [NSArray arrayWithObjects:@"foo", @"bar"]; That message should have a nil after the last argument. With this warning turned on, the compiler will point out that I don't. The ostensible main reason to turn this on is to have the compiler check your uses of printf and scanf formats. I don't use printf often (and I never use scanf ), so that's not so important for me, but when I do, this could come in handy. Sadly, it doesn't work on NSLog calls. This has been fixed in Clang as of 2013. Your printf , NSLog , and stringWithFormat calls all get checked (despite the name of the setting not having changed).

Undeclared Selector Warn if a " @selector(...) " expression referring to an undeclared selector is found. A selector is considered undeclared if no method with that name has been declared before the " @selector(...) " expression, either explicitly in an @interface or @protocol declaration, or implicitly in an @implementation section. Another benefit of this warning is that you can use it to get a warning when you pass a wrong key to a KVC, KVO, KVV, or Bindings method. Uli Kusterer has a macro for that.

Unused Functions Warn whenever a static function is declared but not defined or a non-inline static function is unused. Works best with a policy of declaring any function as static that you don't need to be visible elsewhere in your program.

Unused Labels

Unused Values