Когда использовать NSIn teger против In t
Когда я должен использовать NSInteger
против int при разработке для iOS? Я вижу в примере кода Apple, они используют NSInteger
(или же NSUInteger
) при передаче значения в качестве аргумента функции или возвращении значения из функции.
- (NSInteger)someFunc;...
- (void)someFuncWithInt:(NSInteger)value;...
Но внутри функции, которую они просто используют int
отслеживать стоимость
for (int i; i < something; i++)
...
int something;
something += somethingElseThatsAnInt;
...
Я читал (мне сказали), что NSInteger
это безопасный способ ссылки на целое число в 64-битной или 32-битной среде, так зачем использовать int
совсем?
8 ответов
Вы обычно хотите использовать NSInteger
когда вы не знаете, какую архитектуру процессора может выполнять ваш код, вы можете по какой-то причине захотеть максимально возможный int
тип, который в 32-битных системах является просто int
в то время как в 64-битной системе это long
,
Я бы придерживался использования NSInteger
вместо int
/long
если вы специально не требуете их.
NSInteger
/NSUInteger
определяются как * динамические typedef
*s к одному из этих типов, и они определены следующим образом:
#if __LP64__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
Что касается правильного спецификатора формата, который вы должны использовать для каждого из этих типов, см. Раздел "Руководство по программированию строки" в разделе "Зависимости платформы".
Зачем использовать int
совсем?
Apple использует int
потому что для переменной управления цикла (которая используется только для управления итерациями цикла) int
Тип данных в порядке, как по размеру типа данных, так и по значениям, которые он может содержать для вашего цикла. Здесь не требуется тип данных, зависящий от платформы. Для управляющей переменной цикла даже 16-битный int
будет делать большую часть времени.
Apple использует NSInteger
для возвращаемого значения функции или для аргумента функции, потому что в этом случае тип данных [размер] имеет значение, потому что то, что вы делаете с функцией, это передача / передача данных с другими программами или с другими частями кода; см. ответ на вопрос Когда я должен использовать NSInteger против INT? в самом вашем вопросе...
они [Apple] используют NSInteger (или NSUInteger) при передаче значения в качестве аргумента функции или возвращении значения из функции.
OS X является "LP64". Это означает, что:
int
всегда 32-битный
long long
всегда 64-битный
NSInteger
а также long
всегда размером с указатель. Это означает, что они 32-разрядные в 32-разрядных системах и 64-разрядные в 64-разрядных системах.
Причина существования NSInteger заключается в том, что многие устаревшие API неправильно используются int
вместо long
для хранения переменных размером с указатель, что означало, что API пришлось изменить с int
в long
в их 64-битных версиях. Другими словами, API будет иметь разные сигнатуры функций в зависимости от того, компилируете ли вы для 32-битной или 64-битной архитектуры. NSInteger
намеревается замаскировать эту проблему с помощью этих устаревших API.
В вашем новом коде используйте int
если вам нужна 32-битная переменная, long long
если вам нужно 64-разрядное целое число, и long
или же NSInteger
если вам нужна переменная размером с указатель.
Если вы копаетесь в реализации NSInteger:
#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif
Проще говоря, typedef NSInteger делает шаг за вас: если архитектура 32-битная, она использует int
, если он 64-битный, он использует long
, Используя NSInteger, вам не нужно беспокоиться об архитектуре, на которой работает программа.
Вы должны использовать NSIntegers, если вам нужно сравнить их с постоянными значениями, такими как NSNotFound или NSIntegerMax, так как эти значения будут отличаться в 32-разрядных и 64-разрядных системах, поэтому значения индекса, числа и т. П.: используйте NSInteger или NSUInteger.
В большинстве случаев использование NSInteger не повредит, за исключением того, что он занимает вдвое больше памяти. Влияние на память очень мало, но если у вас есть огромное количество чисел, плавающих в одно и то же время, это может иметь значение для использования целых чисел.
Если вы используете NSInteger или NSUInteger, при использовании строк форматирования вы захотите привести их к длинным целым или длинным целым без знака, так как новая функция Xcode возвращает предупреждение, если вы попытаетесь выйти из NSInteger так, как если бы он имел известную длину. Точно так же вы должны быть осторожны при отправке их переменным или аргументам, которые вводятся как целые, так как вы можете потерять некоторую точность в процессе.
В целом, если вы не ожидаете, что сотни тысяч их будут в памяти одновременно, проще использовать NSInteger, чем постоянно беспокоиться о разнице между ними.
На iOS это в настоящее время не имеет значения, если вы используете int
или же NSInteger
, Это будет иметь большее значение, если / когда iOS перейдет на 64-битную версию.
Проще говоря, NSInteger
с int
s в 32-битном коде (и, следовательно, в 32-битном коде) и long
на 64-битном коде (long
s в 64-битном коде имеют ширину 64 бит, но 32-битный в 32-битном коде). Наиболее вероятная причина использования NSInteger
вместо long
это не сломать существующий 32-битный код (который использует int
с).
CGFloat
имеет ту же проблему: на 32-битной (по крайней мере на OS X), это float
; на 64-битной, это double
,
Обновление: с появлением iPhone 5s, iPad Air, iPad Mini с Retina и iOS 7 теперь вы можете создавать 64-битный код на iOS.
Обновление 2: также с использованием NSInteger
s помогает с совместимостью кода Swift.
На данный момент (сентябрь 2014 г.) я бы рекомендовал использовать NSInteger/CGFloat
при взаимодействии с iOS API и т. д., если вы также создаете свое приложение для arm64. Это связано с тем, что при использовании float
, long
а также int
типы.
ПРИМЕР: FLOAT/DOUBLE против CGFLOAT
В качестве примера мы берем метод делегата UITableView tableView:heightForRowAtIndexPath:
,
В 32-битном приложении оно будет работать нормально, если оно написано так:
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
float
32-битное значение, а возвращаемое вами 44 - 32-битное значение. Однако, если мы скомпилируем / запустим этот же кусок кода в 64-битной архитектуре arm64, 44 будет 64-битным значением. Возвращение 64-битного значения, когда ожидается 32-битное значение, даст неожиданную высоту строки.
Вы можете решить эту проблему с помощью CGFloat
тип
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
Этот тип представляет 32-битный float
в 32-битной среде и 64-битной double
в 64-битной среде. Поэтому при использовании этого типа метод всегда будет получать ожидаемый тип независимо от среды компиляции / среды выполнения.
То же самое верно для методов, которые ожидают целые числа. Такие методы будут ожидать 32-разрядного int
значение в 32-битной среде и 64-битной long
в 64-битной среде. Вы можете решить этот случай, используя тип NSInteger
который служит int
или long
основанный на среде компиляции / времени выполнения.
int = 4 байта (фиксированный независимо от размера архитектора) NSInteger = зависит от размера архитектора (например, для 4-байтового архитектора = 4 байта размера NSInteger)