I understand exactly why unused variable warnings occur. I don't want to suppress them in general, because they are incredibly useful in most cases. However, consider the following (contrived) code.
NSError *error = nil;
BOOL saved = [moc save:&error];
NSAssert1(saved, #"Dude!!1! %#!!!", error);
Xcode reports that saved is an unused variable, when of course it isn't. I suspect this is because NSAssert1 is a macro. The NS_BLOCK_ASSERTIONS macro is not defined, so Objective C assertions are definitely enabled.
While it doesn't hurt anything, I find it untidy and annoying, and I want to suppress it, but I'm not sure how to do so. Assigning the variable to itself gets rid of the compiler warning, but I'd rather do it the "right" way if such a thing exists.
I'm unsure if it's still supported in the new LLVM compiler, but GCC has an "unused" attribute you can use to suppress that warning:
BOOL saved __attribute__((unused)) = [moc save:&error];
Alternatively (in case LLVM doesn't support the above), you could split the variable declaration into a separate line, guaranteeing that the variable would be "used" whether the macro expands or not:
BOOL saved = NO;
saved = [moc save:&error];
Using Xcode 4.3.2 and found out that this seems to work (less writing)
BOOL saved __unused;
In Xcode you can set the warnings for "Unused Variables." Go to "Build Settings" for the target and filter with the word "unused"
Here is a screenshot:
I suggest you only change it for Debug. That way you don't miss anything in your release version.
NSError *error = nil;
BOOL saved = [moc save:&error];
NSAssert1(saved, #"Dude!!1! %#!!!", error);
#pragma unused(saved)
Try like this.
It is working for me. It will work for you, too.
The only simple and portable way to mark variable as used is… to use it.
BOOL saved = ...;
(void)saved; // now used
You may be happy with already described compiler-specific extensions, though.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
NSUInteger abc; /// Your unused variable
#pragma clang diagnostic pop
SOURCE
try with: __unused attribute. Works in Xcode 5
This is the way you do it in C and therefore also Objective-C.
Even though you do not have warnings enabled, it's always a good idea to mark the return value as explicitly ignored. It also goes to show other developers, that you have not just forgotten about the return value – you have indeed explicitly chosen to ignore it.
(void)[moc save:&error];
EDIT: Compilers ignore casts to void, so it should not affect performance – it's just a nice clean human annotation.
You can set "No" LLVM compliler 2.0 warning on "Release"
Make it take up two lines. Separate the declaration and default value
BOOL enabled = NO;
// ...
BOOL enabled;
enabled = NO;
Related
NSArray rather dislikes being passed a nil object as part of its constructor:
UIView *aView;
UIView *aSecondView = [[UIView alloc] init];
NSArray *array = #[aView, aSecondView];
will throw an exception at runtime when array is created.
Does clang have any facilities to try and detect this kind of error? For some trivial cases (like the one above: a stack-local variable that's never assigned to), it seems like the sort of problem the static analyzer would hit out of the park.
TL;DR: -Wuninitialized catches that specific example, __attribute__((nonnull)) for parameters to functions/methods would help catch nil as argument in general.
For this specific example (variable not specifically initialized), you can use -Wuninitialized to catch those uses:
○ xcrun clang a.m -F/System/Library/Frameworks -c -o a.o -Wuninitialized
a.m:6:22: warning: variable 'aView' is uninitialized when used here [-Wuninitialized]
NSArray *array = #[aView, aSecondView];
^~~~~
a.m:4:16: note: initialize the variable 'aView' to silence this warning
NSView *aView;// = nil;
^
= nil
1 warning generated.
For passing nullptr/NULL/nil to functions/methods, __attribute__((nonnull)) should work for most cases. Since this is an API provided by Apple, you would need to file a radar and hope they add it.
P.S: Actually, __attribute__((nonnull)) wouldn't “simply work”, in this case (if you initialized aView to nil, for example. The #[...] sequence seems to be creating an array, and calling +[NSArray arrayWithObjects: count:], where you would be able to mark the first argument as nonnull, but not the things pointed to by it. In any case, it should be relatively simple to write a clang pass for the analysis you mention. You should file a radar, since such a pass could avoid lots of time losses.
P.P.S: It seems __attribute__((nonnull)) doesn't propagate much information, which is sad. :-( If you have a function f(type arg __attribute__((nonnull))) and you pass it a variable which you initialized to nil and never touched again, it doesn't warn.
I believe you are right, Clang static analyzer hit this error out of the park. It is built into Xcode (6 Beta as I tested on). Go Building Settings > Static Analyzer - Analysis Policy > Set Analyze During 'Build' to Yes. To manually perform, go Product > Analyze.
Static analyzer can also be used as stand alone tool in command line. Other option to analyze at compile time is to add Run Script in Build Phases before Compile Sources.
Is there a way I can get a warning when I'm assigning a variable instead of checking equality? There have been many times where I have accidentally assigned, rather than compared, and it would be great to have a warning!
Is there a way Xcode can warn me without having to change coding styles to:
if (YES == aVariable) {...}
Xcode already warns you if you use = instead of == in an if statement in most cases. If you're not getting the warning, tell us what version of Xcode you're using, how old your project is, and what build settings you have changed from their defaults.
My test: I created a brand new iOS app in Xcode 4.5.2 and didn't change any build settings. I just added a little code to application:didFinishLaunchingWithOptions: to trigger the warning. Here it is:
You can disable the warning by setting the compiler's -Wno-parentheses flag (but why would you want to?). You can suppress the warning in a particular case by adding an extra set of parentheses around the assignment:
if ((x = 7)) {
There are two cases where you don't get the warning by default. First, in an init method, you can assign to self, like this:
- (id)init {
if (self = [super init]) { // no warning by default
...
Second, in any context, you can assign the result of the nextObject selector, like this:
while (object = [enumerator nextObject]) { // no warning by default
You can enable warnings in these cases by setting the compiler's -Widiomatic-parentheses flag.
The compiler flag Wparentheses should do the trick. It will force you to place parentheses around assignments in a conditional in order to compile. Clang has this flag set by default.
bool kDebuggingEnabled = NO;
...
for(i=0; i<length; i++){
...
if (kDebuggingEnabled) {
NSLog (#"Value of variable # %i",$resultingOptions);
}
}
whenever my app is live, my code checks the condition every time regarding NSLog.
Is there any better way to improve performance of my code?
You could use preprocessor macros to turn logging on and off. A good example is the DLog macro from Marcus Zarra on the Cocoa is My Girlfriend blog.
#ifdef DEBUG
#define DLog(...) NSLog(#"%s %#", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])
#else
#define DLog(...) do { } while (0)
#endif
You would place the above in your prefix.pch file and then simply replace NSLog statements with DLog statements. You also need to make sure that DEBUG is set in your debug build configuration.
Using preprocessor macros like this means that the logging code does not get compiled into your release build so there is no performance hit for the log statements.
The blog post also contains some other useful macros for handling assertions.
You have 3 choices:
1) if you want to enable/disable your logs at build time. The preprocessor solutions are the best:
// define MY_ENABLE_LOGS in your build settings for the debug configuration only, for example
#ifdef MY_ENABLE_LOGS
#define MYLog(...) NSLog(__VA_ARGS__)
#else
#define MyLog(...) do { } while(0)
#endif
2) if you want to be able to enable/disable logs at runtime (e.g. based on some hidden preferences), your solution is likely the best. You can try to hint the compiler to optimize things a bit, though:
// tell the compiler it's unlikely that kDebuggingEnabled will be true
#define MYLog(...) do { if (__builtin_expect(kDebuggingEnabled, 0)) { NSLog(__VA_ARGS__); } } while(0)
3) last option is a little bit more complicated but can provide richer info than just logs and only depends on the kind of logging you expect to provide. The idea is to use custom probes with dtrace (which can also be used within Instruments). This only works in OS X (not in iOS). See http://www.macresearch.org/tuning-cocoa-applications-using-dtrace-custom-static-probes-and-instruments for example.
Note that you can mix 1) and 2) depending on your needs. 3) is meant to be almost zero cost when probes are not traced and can provide much richer info than a simple log string.
One caveat with these solutions: the arguments of the logs won't be evaluated when MY_ENABLE_LOGS is not defined which might change your application behavior.
Use a preprocessor macro to check if you're building for debug:
#if DEBUG
// do stuff
#end
If the preprocessor (the thing that runs before the compiler) evaluates DEBUG to be true it'll keep the code there for the compiler to compile, but if DEBUG doesn't exist or is false, it'll erase that piece of code.
Occasionally, during development/debugging, I want to ensure that an object is of a certain type:
PageTopBottom *newPage = [notification object];
assert([newPage isKindOfClass:[PageTopBottom class]]);
which I've worked into this
#define assertType(_var_, _class_) assert([_var_ isKindOfClass:[_class_ class]])
and
PageTopBottom *newPage = (id)[notification object];
assertType(newPage, PageTopBottom);
but now I'd like to, if possible, just use
assertType(newPage)
Is it possible to get information about a variable's declared type from the variable?
I'm not positive that I'm framing the question correctly, but any answer that gets me to be able to assertType with one parameter would be great.
Is it possible to get information about a variable's declared type from the variable?
No. By the time the program is running, that information is lost. In your case, newPage is just a 32 or 64 bit number that points to a bit of memory that holds an Objective-C object.
I think your original unmacro'd version is the right thing to do here:
assert([newPage isKindOfClass:[PageTopBottom class]]);
That perfectly documents the assumption you are making i.e. that you assume newPage is an instance of PageTopBottom or one of its subclasses and it's completely clear to anybody who understands Objective-C. Your macro version slightly obfuscates that, in that somebody coming across it in the code might beleive it is asserting that newPage is a PageTopBottom and not one of its subclasses (you could change the name of the macro to prevent that, I suppose, but I just wouldn't bother).
Edit
What you could do is combine the declaration and assertion in one:
#define DECLARE_AND_ASSERT_IS_KIND_OF_CLASS(T, V, I) T* V = (T*)(I); assert([(V) isKindOfClass: [(T) class])
which would work like this:
DECLARE_AND_ASSERT_IS_KIND_OF_CLASS(PageTopBottom, newPage, [notification object]);
Hmm, with Objective-C++ there are two options:
Write a template function
template void assertType(T* obj) { ... }
For a pointer X* x, use NSClassFromString([NSString stringWithUTF8String:typeid(*x).name()]).
Without using C++, you might be able to use GCC extension typeof, but I'm not sure if [typeof(*x) class] is a legit operation...
The preprocessor only processes text; it has no knowledge of type, which is why it's sometimes considered 'dangerous'. The only way I could see doing it is wrapping the variable declarations in a macro, which I would strongly advise against, and probably wouldn't actually cut down on the code or complexity.
Also, shouldn't you check the type before casting?
Xcode looked at this line and did not complain. Project built, code crashed at runtime.
NSString *randomName = [NSString stringWithFormat:#"%#, %#, %#",
[randomAjectiveList objectAtIndex:ajectiveIndex],
[randomNounList objectAtIndex:nounIndex]];
Naturally, come to think about it, i have one too many "%#" in place, one more then actual arguments. Correct code should look as follows
NSString *randomName = [NSString stringWithFormat:#"%#, %#",
[randomAjectiveList objectAtIndex:ajectiveIndex],
[randomNounList objectAtIndex:nounIndex]];
I ask you though ... why didn't Xcode complain? Seems like such an obvious thing to do with param counters. Shouldn't this be checked at compile time? Is it specific to "%#", perhaps?
Please advise.
Based on a quick check, you're 100% right that this isn't checked at compile time, seemingly even by the static analyser. Conversely, NSLog is checked. So on my machine, with XCode 4.0.2, the following:
[NSString stringWithFormat:#"%d %# %#"];
NSLog(#"%d %# %#");
Produces a warning on the NSLog of "More '%' conversions than data arguments" but fails to comment on the NSString.
So, the difference could be fixed function calls versus dynamic calls. The compiler can't actually be completely certain where the NSString call will go because it's possible you'll have declared a category or used the low-level runtime to adjust the NSString selector table at runtime.
However, especially given the problems you'll almost immediately encounter if you start modifying the behaviour of the Foundation classes, like you I'd have expected at least a warning.