Should i cast with NSInteger, NSNumber, and NSUinteger? - objective-c

In objective c, I often run into warnings in the compiler when I have methods that (for instance) return/take as an argument an NSInteger, and I instead place the argument as say a long int/NSNumber/etc value or variable. The code compiles fine, but I am always tempted to just do casts because the warnings make me uneasy. I understand that it probably does not make a big difference either way, but is casting the preferred way to handle these warnings or not?

int, NSInteger, and NSUInteger are scalars. NSNumber is an object. They have nothing to do with one another, and casting between them to hide that fact from the compiler will bring disaster.
Remember, casting means that you throw away the compiler's ability to check that you are doing the right thing. You can use casting to lie to the compiler, as if to say to it, "Don't worry, everything will be okay." Do not lie to the compiler! If you do, then when the app runs, you will get nonsense at worst, and a crash at best. (The crash is best, because it stops you dead; not crashing means you now have a big mistake that will be very difficult to track down later.)

If the warning is just a cast issue then by all means add the cast. Many times Xcode is very helpful with this.
Many times the best answer is to change the declared type so there is neither an error nor a warning. Example: You have declared a variable as an int. A method is expecting a NSInteger. Instead of a cast change the declaration of the variable to an NSInteger.
But note that casting an NSNumber to an NSInteger for example will not fix anything, as #Josh points out they are very different things.
Eliminate all warnings! Then when a new one occurs it is readily apparent. If there are warnings then the code is not compiling fine.
Note: There are times when individual warnings will need to be eliminated with a #pragma but these are extremely rare and only done when the cause is completely understood. An example: I needed to be able to cause a crash in an application for testing, that code caused a warning, a #pragma was added to eliminated the warning.
Also run Analyzer and fix any warnings there.
The warnings are there for a reason, they help catch errors.

Related

Is there any compiler option that disables the warning you get when you initialise a structure inline?

I'm looking for a compiler setting that will allow me to do this:
[imageGraphEraserIcon imageByResampling:{20, 20} zoom:3]; without throwing a warning. Now I have to do this all the time and the casting seems pointless since the compiler should know the type to expect:
[imageGraphEraserIcon imageByResampling:(CGSize){20, 20} zoom:3];
I know about "CGSizeMake", I'm looking for a shorter way, more pleasant to the eye to do it.
while what you have constructed will work but the correct Objective-C pattern is:
[imageGraphEraserIcon imageByResampling:CGSizeMake(20, 20) zoom:3];
The fact is Apple make the compiler, if you're getting a warning you're "doing it wrong". The compiler expects you to write CGSizeMake for its type checking. Therefore that is the convention. There is no reason to prefer the anonymous struct. It makes your code less standard and harder for others to understand your intent.

GCC / LLVM compilation optimization on casts?

I'm writting a series of anonymous functions for an objective-C project (i.e. these functions are not class specific / implementation is hidden) and I came across an interesting issue...
I have a macro function:
div(c)((CGFloat)c/255.0f)
This usage will almost always be something like div(0.0f), but others may not know that it takes a float so div(0) is possible
and the question I have is this: when variables are explicitly cast and the variable is of the same type as the cast is any performance lost to the cast?
A cast is a promise, not a data type, not a method, not an extension. You're just making the compiler comfortable about a type. Nothing should change execution-wise, therefore there is nothing to optimize execution-wise. If you're worried about the type of the parameter you've requested, you can always explicitly store it in a different CGFloat before operating on it.
The machine works with memory. At the end all the variable that you use are just raw bytes.
Then why do Objective-C have types? To protect the programmer at compile time, showing errors and warnings.
At runtime all the operations that you do are made on the memory, so you don't need to worry about the overhead of casts.

Why is 'no known method for selector x' a hard error under ARC?

Maybe it's useful if calling a method that MyClass doesn't understand on a something typed MyClass is an error rather than a warning since it's probably either a mistake or going to cause mistakes in the future...
However, why is this error specific to ARC? ARC decides what it needs to retain/release/autorelease based on the cocoa memory management conventions, which would suggest that knowing the selector's name is enough. So it makes sense that there are problems with passing a SEL variable to performSelector:, as it's not known at compile-time whether the selector is an init/copy/new method or not. But why does seeing this in a class interface or not make any difference?
Am I missing something about how ARC works, or are the clang warnings just being a bit inconsistent?
ARC decides what it needs to retain/release/autorelease based on the cocoa memory management conventions, which would suggest that knowing the selector's name is enough.
This is just one way that ARC determines memory management. ARC can also determine memory management via attributes. For example, you can declare any typedef retainable using __attribute__((NSObject)) (never, ever do this, but it's legal). You can also use other attributes like __attribute((ns_returns_retained)) and several others to override naming conventions (these are things you might reasonably do if you couldn't fix the naming; but it's much better to fix the naming).
Now, imagine a case where you failed to include the header file that declares these attributes in some files but not others. Now, some compile units (.m files) memory manage it one way and some memory manage it another. Hijinks ensure. This is much, much worse than the situation without ARC, and the resulting bugs would be mindbending because some ARC code would do one thing and other ARC code would do something different.
So, yeah, don't do that. (Of course you should never ignore warnings in Objective-C anyway, but this is a particularly nasty situation.)
It's an ounce of prevention, I'd assume. Incidentally, it's not foolproof in larger systems because selectors do not need to match and matching is all based on the translation, so it could still blow up on you if you are not writing your program such that it introduces type safety. Something is better than nothing, though!
The compiler wants to know about parameters and return types, potentially annotations and out parameters. ObjC has defaults to fall back on, but it's a good source of multiple types of bugs as the compiler does more for you.
There are a number of reasons you should introduce type safety and turn up the warning levels. With ARC, there are even more. Regardless of whether it is truly necessary, it's a good direction for an objc compiler to move towards (IMHO). You might consider C99 safer than ObjC 2.0 in this regard ;)
If there really is a restriction for codegen, I'd like to hear it.

Why does a passed-by-value struct parameter get corrupted?

This isn’t the original code (I stripped things back in trying to simplify for debugging), but it does display the problem. On the face of it, looks simple enough:
- (void) testMethod: (TouchData) toi {
TouchData newToi = toi;
NSString *test = #"test string";
NSLog(#"string: %#", test);
// in ‘real’ code I pass the struct back
// It’s void here for the simplest possible
// case
}
TouchData is a struct, declared thus:
typedef struct {
Entity *owner;
CGPoint startPos;
CGPoint latestPos;
CGPoint startOfStraightSwipePos;
NSTimeInterval startTime;
NSTimeInterval latestTime;
NSTimeInterval startOfStraightSwipeTime;
CGFloat latestSpeed;
NSMutableArray *gestures;
BOOL isOfInterest;
} TouchData;
When I step through testMethod in the debugger (watching toi) on hitting NSLog (which doesn't even involve toi), all toi member values suddenly zero out. This doesn’t happen to the copy (newToi). It doesn’t happen if I pass the struct in by reference. It doesn’t happen if replace the testMethod invocation directly with the method body (ie. if I run these lines in situ rather than calling into a method). It doesn’t happen if I change the toi parameter type to a dummy struct with a couple of int members, created just before the call.
It might worth pointing out that testMethod is only called from within its own
class, and that the caller has just extracted the struct from an NSMutableDictionary (via unboxing an NSValue). But given that (a) the struct is
passed into the method here by value, and (b) that on entry its members as shown
by the debugger are all as expected, I don’t see that this can be causing a problem. There is also the thorny issue of the two object pointers in the struct, but in other contexts they’re working out OK, and they check out in the debugger on entry to the method, so I don’t think I’ve missed essential retains.
I presume I’m running into some kind of heap or stack corruption, but I’ve no idea how or why. I’m new to Objective-C, and have previously worked in
garbage collected environments, so my memory management experience is limited. It’s entirely possible that I’ve missed something painfully obvious.
I expect someone will tell me to make TouchData an object type instead, and indeed I may well go that way. I also have a couple of tested workarounds, ie. to either work on a copy, or pass the struct in by ref. But I’d really like to know what’s going on here.
If toi is not used after the line TouchData newToi=toi, the compiler can do whatever it wants to do in the stack memory where toi originally was placed after that line. For example, it might reuse the stack memory when calling another function, in this case NSLog.
So, watching toi by a debugger might show something strange. The compiler does often do these things, in particular if the optimization is turned on. Even with no optimization there's no guarantee that the stack location of toi is left intact after it's last used.
By the way, you said having object pointers inside toi didn't cause problems, but it's a tricky situation and I recommend strongly against that practice. Follow the standard retain/release rules; otherwise, another programmer who takes a look at your code (who might be yourself two years from now) would be totally confused. Also, the static analyzer (which can be accessed by doing Build & Analyze in XCode) might be confused and might give false positives. So, don't do that.

Quick question about casting basic return types

I find myself casting return types alot to silence compiler warnings and it always makes me feel like i'm doing something wrong.
This example is Objective-c
const char *strBuf = [anNString UTF8String];
[anOutputStream write:strBufr maxLength:len];
This goves me a compiler warning as
-UTF8String returns const char * and -write:maxLength: takes const uint8_t *
So, knowing no better i would usually add the cast to stop the nagging and carry on my merry way.
Is this bad style (on my part), or just the way it is?
I appreciate any thoughts or advice.
There is no way around this. C, C++, and Objective-C are strongly typed languages. So, anytime there's a type conversion like that, you're going to get a compiler warning. The only way around it is to use the same types which is not always possible. It's typical. I would keep doing what you're doing. Don't ignore the warnings or turn them off because there will be one type conversion that will be an error that you will want to fix. If you turn of the warnings, you're leaving yourself vulnerable to getting a bug that will be very hard to find.
This kind of casting is kind of ugly but it's the most general way to deal with these kind of type mismatches. Some compilers provide other ways of silencing these warnings, but turning them off is a bad idea because sometimes they really matter. Casting acknowledges the difference and makes sure you've thought about any possible consequences.
(Do think about the consequences. If you just unthinkingly cast things can go badly wrong. But you're not doing that, it doesn't seem.)