Wednesday, September 30, 2009

The number of the beast

As you may have noticed, I get a little bit obsessed. Right now, I'm working hard on Cocoa, next month it'll probably be something else. And I want to use the blog as a way to (in Bill Bumgarner's memorable phrase) "so Google can organize my head." This post is tagged "Instant Cocoa." The idea is to present a short, succinct exploration of some aspect of Cocoa with working code. Now, that code may break in the future, but it seems like a good idea right now.

And a disclaimer: these posts are for someone exactly like me. In fact, they are for me. If you know anything about Cocoa, you are probably wasting your time. But if you're struggling with the documentation and overly complex examples, you've come to the right place.


NSNumber

NSNumber provides a way of storing a value (the docs say: "a signed or unsigned char, short int, int, long int, long long int, float, or double or a BOOL." You can't do math with these things, but you can store them in an array and write them to disk, very useful indeed. You can also compare them, and get them back out again when you need them.

So I had a couple of questions:

• what 's the difference between the class method and instance method for getting a new number?

+ (NSNumber *)numberWithInteger:(NSInteger)value
- (id)initWithInteger:(NSInteger)value


• why is there a method for int and also a method for integer?

• I saw a discussion of something funny going on with NSNumber, and I thought I'd explore it. See below.

You can copy and paste the code listing into a text file. Save it and compile it from the command line as indicated. In the first part, we do alloc..init. That means in the classical memory environment (as here b/c we compiled without garbage collection), we own the NSNumber and must should release it when we're done with it.

Curiously, this freshly minted NSNumber has a retainCount of 2. I thought we owned it, but it looks like we we're just renting...

After that we get a second NSNumber using the same integer value (1) by the class "convenience" method. This code fails unless we set up the autorelease pool beforehand. Something very wild happens. It has a retainCount of 3, and remarkably, the retainCount of our first NSNumber has also gone up. Can you guess?

We really shouldn't, but let's do a retain on the first number in the second part of the code. Once again, the retainCount of both NSNumbers is incremented. What's going on? A peek at the addresses of the objects reveals the magic: they actually are the same thing! Here's the output (stripped of the date/time info from NSLog):

n1=1 count=2
n1=1 count=3 n2=1 count=3
n1=1 count=4 n2=1 count=4
0x100108ce0 0x100108ce0
break on 13


The last line of the output results from the third section of code. We go through the integers one-by-one until the NSNumbers we get from calls to the class method are different. This happens when i = 13. For 0 through 12 they are identical. It's a baker's dozen.


// gcc -o test test4.m -framework Foundation
// ./test
// no garbage collection

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
NSNumber *n1 =
[[NSNumber alloc] initWithInteger:1];
NSLog(@"n1=%@ count=%u",n1,[n1 retainCount]);

NSAutoreleasePool * pool =
[[NSAutoreleasePool alloc] init];
NSNumber *n2 =
[NSNumber numberWithInteger:1];

NSLog(@"n1=%@ count=%u n2=%@ count=%u",
n1,[n1 retainCount],n2,[n2 retainCount]);

[n1 retain];
NSLog(@"n1=%@ count=%u n2=%@ count=%u",
n1,[n1 retainCount],n2,[n2 retainCount]);
NSLog(@"%p %p",n1,n2);

NSNumber *x;
NSNumber *y;
NSString *s;
NSString *t;
NSUInteger i;
for (i=0; i<100; i++) {
x = [NSNumber numberWithInteger:i];
y = [NSNumber numberWithInteger:i];
s = [NSString stringWithFormat:@"%p",x];
t = [NSString stringWithFormat:@"%p",y];
if (!([s isEqual:t])) {
break;
}
}
NSLog(@"break on %u", i);
[pool drain];
return 0;
}


[blogger is doing weird sh*t with the indentation on my code. Sorry about that. Let me know if something doesn't work for you.] And let me know if you have a better idea about code posting in html.