Subtitle: why does this code work? It seems to allow comparison of NSNumber with NSString types via some sort of coercion. I’m trying to compare a selection from a UISegmentedControl with a previously stored value.
- (IBAction)minSegmentedControlChanged:(id)sender // MINIMUM value
{
UISegmentedControl *s1 = (UISegmentedControl *)sender;
NSMutableArray *pD = [[GameData gameData].curData valueForKey:@"persData"];
// Must make sure max >= min
NSNumber *currMax = [pD objectAtIndex:1];
NSLog(@"%@", [currMax class]); // __NSCFString ?!
int ss1 = s1.selectedSegmentIndex;
NSNumber *SS1 = [NSNumber numberWithInt:ss1 + 2];
if (SS1 >= currMax) SS1 = currMax;
NSLog(@"%@", SS1); // Answer is correct, appears to be an integer
NSLog(@"%@", [SS1 class]); // __NSCFString ?!
[pD replaceObjectAtIndex:0
withObject:SS1];
[[GameData gameData].curData setObject:pD
forKey:@"persData"];
NSLog(@"%@", [[GameData gameData].curData valueForKey:@"persData"]);
}
I am particularly asking about:
NSNumber *currMax = [pD objectAtIndex:1];
NSLog(@"%@", [currMax class]); // __NSCFString ?!
which seems to return a string for a number. [[GameData gameData].curData valueForKey:@"persData"]; is initialized as follows:
_persData = [[NSMutableArray alloc] initWithObjects:@"2", @"8", @"TWL", @"0", @"0", nil];
which is a string at element 1. So why can I ask it for an NSNumber, which reports that it is actually a __NSCFString on which I can do arithmetic comparisons on? I’ve only been at objective-c for a few months but this seems strange.
Okay, let’s walk through this one step at a time.
First of all, all of the elements in
_persDataare strings. Period.NSStringis a class cluster, so the concrete classes of the various instances you inquire about may look weird, but that’s to support toll-free bridging and other magic that’s not relevant to this discussion.This line is incorrect. You might think there’s some sort of coercion going on, but actually you’re just assigning an
NSString *to anNSNumber *. Which is wrong, and will explode in your face at the earliest convenience. It so happens thatobjectAtIndex:returns anid, which is stripped of type information, so the compiler is trusting you to store it in the right kind of pointer, but that’s not enforced until you try to send a message to it.This is an extremely wily comparison.
SS1is most certainly anNSNumber, butcurrMaxis anNSString. But we’re not comparing the values of those objects. To do that, we’d use thecompare:method. Instead, we’re comparing them as pointers, looking only at their addresses in memory. By some accident of implementation,SS1seems to always reside at a higher address thancurrMax.If all of the foregoing is true, then
SS1is always of typeNSStringafter the above line is executed, which explains why this line:Always indicates that
SS1is a string.