Logging a NSUInteger breaks xcode [duplicate] - objective-c

This question already has answers here:
"Thread 1: stopped at breakpoint" error when initializing an NSURL object
(3 answers)
Closed 8 years ago.
I'm doing a tutorial on codeschool http://tryobjectivec.codeschool.com/ and according to this tutorial the following code should work:
void (^sumNumbers)(NSUInteger, NSUInteger) = ^(NSUInteger num1, NSUInteger num2){
NSLog(#"The sum of the numbers is %lu", num1 + num2);
};
Well, I tried the let this work, allthough xcode already gave me some orange error message:
I tried to build the code anyway, just to see if xcode was right or the tutorial was right. Well, something broke:
But even worse, I can't get xcode fixed again, xcode now pretends that all my code that I've ever wrote is causing problems. But I'm pretty sure it used to work:

NSUInteger is, at least in a 32-bit architecture, typedefed as an unsigned int, not a long. The %lu formatter specifies that you want to print them as longs, so there's a type conflict. If you print them as %ud, which is an unsigned int.
The blue marker in the gutter of the line sumNumbers(10,20); indicates that you have a breakpoint set on that line, which causes the interruption of the app. Remove/disable that breakpoint and that will work fine as well.

It is generally advised that you do not use NSInteger, NSUInteger, CGFloat, or CFIndex as direct parameters to an NSLog, or any other operation using a printf-style formatter. The reason is that their size varies between 32 and 64 bit architectures.
In your case, the correct way to write the code is to cast the NSUInteger to an unsigned long which is 64 bits on both architectures, at least as far as the XCode toolchain is concerned. Be warned that this may not be the case on other systems - for example, the C++ standard only requires that a long be at least 32 bits in size.
void (^sumNumbers)(NSUInteger, NSUInteger) = ^(NSUInteger num1, NSUInteger num2){
NSLog(#"The sum of the numbers is %lu", (unsigned long)(num1 + num2));
};
With regard to the tutorial, the person who wrote it was probably working on a 64 bit system, so NSUInteger mapped to the size required by %lu. Everything you read on the Web, from Apple documentation to Stack Overflow answers will have errors somewhere.

In order to NSLog your NSUInteger, you should change your statement to this:
NSLog(#"%ud", num1 + num2);
The reason your app is not running properly anymore is probably because you still have your breakpoint set. Go to Debug > Deactivate Breakpoints or use the shortcut ⌘Y, and then try running your application.

Related

Objective-C: Type casting object to integer_t

integer_t is a typedef of int32_t as defined here, and after some checking, integer_t has a size of 4 bytes, and so does int (intValue) as per mentioned is this doc. My question is, is casting like this produce valid result?
integer_t value = 100;
id anObject = #(value);
integer_t aValue = [anObject intValue];
Is aValue always equal to value? Will this cause any issue in the long run? Should I do long value = [anObject longValue] instead? Thanks in advance.
Short and specific answer - YES those values are equal since integer_t and int both (according to you - here's the catch) have the same size AND the same signedness. If one was e.g. some type of unsigned int then it would not work. Neither would it work if one was e.g. 8 bytes (long) and the other 4 (int).
The long and general answer is - it depends. Yes, here you think it is equal but there are always funny cases you need to watch out for. I already mentioned the size and signedness but the real trip can be over the system architecture. So you might assume they are the same and then one day you compile for 64b arch and all breaks down as int there has 8 bytes length and integer_t still is 4 e.g. You could also run into endianness troubles. Thus if you get a bunch of ints from a mainframe they could be stored BADC where A, B, C and D are the 4 bytes of the int.
As you can see, it is easy to scare anybody working with these, and in practice that is why there are things such as NSInteger - Objective-C's attempt to protect you from these. But don't be scared, these are toothless monsters, unless you work at a low level, and then your work will be to work with them. Doesn't that sound poetic.
Back to the code - don't worry too much about these. If you work in Objective-C, maybe try to use the NSInteger and NSUInteger types for now. If you store these and need to load it again later then you need to think about the possibility that you store it from a 32b arch and restore it on a 64b arch and work around that somehow.

Objective C : can't operate download issue

i'm new to Xcode objective-c and I have a task to make a newsletter that downloadable.
So, I got some source code and tweak a bit but I got some error that said
"Implicit conversion loses integer precision : 'long' to 'int'
here are my code
-(void)downloadIssue:(IssueInfo*)issueInfo{
NewsstandDownloader* downloader = [[AppDelegate instance] newsstandDownloader];
downloader.delegate = self;
long index = [self.publisher indexOfIssue:issueInfo];
[downloader downloadIssue:issueInfo forIndexTag:index]; <-- Error
}
Please help me.
Thank you.
That's just a compiler warning and a mild one at that. If you were dealing with a document that had more than, say, 32000 pages then you might need to be concerned about it.
The way to solve the problem is to either change the declaration of the function you're calling to something like:
[downloader downloadIssue:(IssueInfo *)issueInfo forIndexTag:(long)index]
or, simply use a cast:
int index = (int)[self.publisher indexOfIssue:issueInfo];
"int" isn't usually a good thing to use in Objective C as there are different lengths and capacities to it on different platforms (32 bit versus 64 bit, iOS vs MacOS, etc.). It's better to use something more Objective-C specific, like NSInteger or NSUInteger.

Float variables assigned value from line above

I have an iOS App that is doing things that don't quite make sense to me. I have several float variables defined in my interface that are being assigned incorrectly.
kettleVolume = 30;
lbsGrain = 5;
mashIn = 65;
grainTemp = 20;
When I step through this on the debugger, I very clearly see the following values being assigned-
kettleVolume float 1.09038e-33;
lbsGrain float 30
mashIn float 5
grainTemp float 65
Somehow, they are getting the values from the line above them? What am I doing incorrectly?
There are numerous reports that when inspecting ivars from LLDB they seem wrong (myself had the same problem many times). More specifically they seem to be shifted. That said, it only seems to be a bug in the implementation of XCode's inspector. If you want to be sure about the values you can either po _yourivar in the debugger console, use GDB or NSLog them. There is also a similar question here: GDB Vs LLDB debuggers

Strange BAD_ACCESS when printing NSInteger

this is my first time asking something here, so don't be too harsh on me please :-). I have a strange "bad access" issue. In a class of mine I have a NSInteger along with a few other members. I override the - (NSString *)description method to print the values of everything like so (omitted the unrelevant part):
- (NSString *)description {
return [NSString stringWithFormat:#"Duration:%d", duration];
}
and then I print that using NSLog(#"%#", myObject) which is giving me EXC_BAD_ACCESS without any log messages, regardless of the NSZombieEnabled.
I have double checked the order of all formatting specifiers and
parameters - it's correct.
I tried changing the format specifier to %i and %# and didn't get any result
When I init my object I don't initialize
duration. Later, I assign it through a property #property NSInteger
duration. So I tried initializing the duration to 0 in my init
method but to no avail.
If I box duration to a NSNumber prior to
printing, it works.
When I remove the duration and leave all the
other ivars it works again.
I'm stumped, what am I doing wrong here?
Can you help me?
Thanks a lot!
EDIT: To summarize, It seems this is caused by differences between 32 and 64 bit platforms, because it's fine when run on an iphone 4 and has issues only when run in the simulator. I tried 3 different approaches - using %d and %i with the NSInteger variable itself, using %qi and using %ld/ %lx and I also tried to cast to int and long with the various format specifiers. Every time I can run on the device, but get EXC_BAD_ACCESS in the simulator.
The only guess here: NSInteger could be 64 bit in your case and %i (as well as %d) expects 32-bit integer, you can try %qi or (what seems to be better) cast the value explicitly.
When you run the app in the debugger, where exactly is the signal raised? Xcode will show you the precise line and stack of the problem.
When you are sure the crash happens in the stringWithFormat: method it's probably a matter of format specifiers. Apple's String Programming Guide contains information on how to handle NSInteger in a safe and platform independent way.
Maybe you need to synthesyse your property?

Why does only NSLog warn me about using the %lu string format specifier for NSUInteger?

For some reason, I get a compilation error when I try to do the following:
NSLog(#"row: %lu", indexPath.row);
where row is of type NSUInteger. The error I get is
Conversion specifies type 'unsigned long' but the argument has type 'NSUInteger' (aka 'unsigned int')
I can do the following with no compilation errors:
NSString * string = [NSString stringWithFormat:#"row: %lu", indexPath.row];
I'm using the exact same format string and substitution argument in both cases, but why does NSLog freak out while -stringWithFormat: seems to be perfectly content? My compiler is LLVM 1.6.
All devices that iOS currently runs on are 32-bit. If you want to silence the warning:
NSLog(#"row: %lu", (unsigned long)indexPath.row);
[Edit: As of the iPhone 5s, it is no longer true that iOS is always 32-bit.]
I've run into this same issue, and although #Wevah is correct and his answer works just fine, there's another option that doesn't require any code changes. See the following Apple documentation for details:
String Programming Guide | Platform Dependencies
64-Bit Transition Guide for Cocoa | Building 32-Bit Like 64-Bit
The NS_BUILD_32_LIKE_64 preprocessor macro is quite helpful. You can set it in your Xcode project settings (under GCC_PREPROCESSOR_DEFINITIONS) or just put #define NS_BUILD_32_LIKE_64 1 in your precompiled header (.pch) file. In my app, this eliminated 11 warnings without any code changes.
This works because unsigned int and unsigned long are the same size (4 bytes) on iOS, so changing the typedef of NSUInteger makes the compiler (and the developer) happy, but the hardware doesn't care, since it's just doing integer math in both cases. :-)
Apple documentation recommends casting the 64 bit value to a 32 bit value using %lu and %ld. This poses a problem if you actually use the extra 32 bits. Format strings %qu and %qd specify a 64 bit value (unsigned and signed respectively). If you want code that will compile in either mode, then values declared as NSUInteger or NSInteger will have to be cast to a UInt64 or SInt64 in the parameter list to avoid the warning.