2012-06-26 4 views
1

Subtitle: почему этот код работает? Кажется, это позволяет сравнивать NSNumber с типами NSString через какое-то принуждение. Я пытаюсь сравнить выбор из UISegmentedControl с ранее сохраненным значением.Является ли iOS принуждением NSStrings к NSNumbers?

- (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"]); 

} 

Я особенно с просьбой о:

NSNumber *currMax = [pD objectAtIndex:1]; 
NSLog(@"%@", [currMax class]); // __NSCFString ?! 

который, кажется, возвращает строку для номера. [[GameData gameData].curData valueForKey:@"persData"]; инициализируется следующим образом:

  _persData = [[NSMutableArray alloc] initWithObjects:@"2", @"8", @"TWL", @"0", @"0", nil]; 

, который представляет собой строку в элементе 1. Так почему я могу попросить его для NSNumber, который сообщает, что это на самом деле __NSCFString, на котором я могу делать арифметические сравнения на? Я был на объективе-с в течение нескольких месяцев, но это кажется странным.

+0

Вам потребовалось несколько месяцев, чтобы понять, что цель-c была странной? :) – Nate

+0

С одной стороны - '% @' печатает строку, а не целое число. Мне было бы интересно посмотреть, как вы укажете, какие вы укажете, если вы скажете им печатать как целые числа, используя '% i'. – WendiKidd

+0

Пришел из 'R', так что это было странно в течение долгого времени. Когда вы думаете, что знаете, что-то подобное происходит. Если, конечно, это не «очевидно». –

ответ

8

Хорошо, давайте пройдем через это один шаг за один раз.

Прежде всего, все элементы в _persData являются строками. Период. NSString - кластер классов, поэтому конкретные классы различных инстанций, о которых вы спрашиваете, могут выглядеть странно, но это поддержка бесплатного моста и другой магии, которая не имеет отношения к этому обсуждению.

NSNumber *currMax = [pD objectAtIndex:1]; 

Данная линия является неверной. Вы можете подумать, что происходит какое-то принуждение, но на самом деле вы просто назначаете NSString * на номер NSNumber *. Что неправильно, и взорвется в вашем лице как можно скорее. Так получилось, что objectAtIndex: возвращает id, который лишен информации о типе, поэтому компилятор доверяет вам хранить его в правильном виде указателя, но это не применяется до тех пор, пока вы не попытаетесь отправить ему сообщение.

if (SS1 >= currMax) SS1 = currMax; 

Это очень хитрое сравнение. SS1 - это, безусловно, NSNumber, но currMax - это NSString. Но мы не сравниваем значения этих объектов. Для этого мы использовали бы метод compare:. Вместо этого мы сравниваем их как указатели, глядя только на их адреса в памяти. По некоторым случайным последствиям, SS1, кажется, всегда находится на более высоком адресе, чем currMax.

Если все вышесказанное верно, то SS1 всегда типа NSString после выше линии выполняется, что объясняет, почему эта линия:

NSLog(@"%@", [SS1 class]); 

Всегда указывает на то, что SS1 является строкой.

+0

Спасибо за четкое объяснение. отремонтировать его сейчас и лучше (не pe rfect) понимание. –

+0

+1. Хорошее объяснение. – nhahtdh

+3

+1 для «взорваться в вашем лице при раннем удобстве». –

2

Фактически вы инициализируете NSMutableArray с помощью NSString, а не номера.

Когда вы тянете объект из NSMutableArray с objectAtIndex, тип возвращаемого функцией является id, что она будет слепо отбрасывать к NSNumber, в то время как реальный объект является NSString.

Похоже, что оператор SS1 >= currMax сравнивает адреса объектов, а не их значения.

Вы можете проверить его с этим фрагментом кода:

NSNumber *a = [[NSNumber alloc] initWithUnsignedInt: 34]; 
NSNumber *b = [[NSNumber alloc] initWithUnsignedInt: 3]; 

NSNumber *c = [[NSNumber alloc] initWithUnsignedInt: 34]; 
NSNumber *d = [[NSNumber alloc] initWithUnsignedInt: 234]; 

NSLog(@"%p %p %p %p %d %d", a, b, c, d, a >= b, c >= d); 
+0

Правильно, я инициализировал его как строку. Второе предложение меня немного смущает. Если я не могу поместить его в массив как определенный тип и получить его обратно как один и тот же тип, на что я могу доверять? –

+2

@BryanHanson Вы все равно получите объект «NSString» из массива, но Objective-C слабо типизирован, поэтому вы можете поместить его в любой переменная, которую вы хотите, так как тип возврата - 'id' (иначе он возвращает любой тип объекта). –

+0

@JakeKing Спасибо, это тонкость, которую я, очевидно, не оценил. –

Смежные вопросы