Когда использовать NSInteger против int

когда я должен использовать 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 at все?

8 ответов


вы обычно хотите использовать NSInteger когда вы не знаете, на какой архитектуре процессора может работать ваш код, поэтому вы можете по какой-то причине хотеть максимально возможного int тип, который в 32-битных системах является просто int, в то время как на 64-битной системе это long.

Я бы придерживался использования NSInteger вместо int/long если вы специально не требовать их.

NSInteger/NSUInteger определяются как * dynamic 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 DataType-это хорошо, в размер типа данных и значений он может держать за петлю. здесь нет необходимости в зависимом от платформы типе данных. для переменной управления циклом даже 16-бит int будет делать большую часть времени.

Apple использует NSInteger функции возвращаемое значение для функции аргумент потому что в этом случае тип данных [размер] имеет значение, потому что то, что вы делаете с функцией, передает/передает данные с другими программами или с другими частями кода; см. ответ на когда я должен использовать NSInteger против int? в самом вашем вопросе...

они [Apple] используют NSInteger (или NSUInteger) при передаче значения как аргумент функции или возвращает значение из a функция.


OS X - это "LP64". Это означает, что:

int всегда 32-бит.

long long всегда 64-бит.

NSInteger и long всегда имеют размер указателя. Это означает, что они 32-разрядные в 32-разрядных системах и 64-разрядные в 64-разрядных системах.

причина существования NSInteger заключается в том, что многие устаревшие API неправильно используются int вместо long для хранения переменных размером с указатель, что означало, что API должен был измениться с int to 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

просто, nsinteger typedef делает шаг для вас: если архитектура 32-разрядная, она использует int, если он 64-разрядный, он использует long. Используя NSInteger, вам не нужно беспокоиться об архитектуре, на которой работает программа.


вы должны использовать NSIntegers, если вам нужно сравнить их с постоянными значениями, такими как NSNotFound или NSIntegerMax, поскольку эти значения будут отличаться в 32-разрядных и 64-разрядных системах, поэтому значения Индекса, счетчики и тому подобное: используйте NSInteger или NSUInteger.

в большинстве случаев не помешает использовать NSInteger, за исключением того, что он занимает вдвое больше памяти. Влияние памяти очень мало, но если у вас есть огромное количество чисел, плавающих вокруг в любой момент времени, это может сделать разница в использовании ИНЦ.

Если вы используете NSInteger или NSUInteger, вы захотите разбить их на длинные целые или беззнаковые длинные целые при использовании строк формата, так как новая функция Xcode возвращает предупреждение, если вы пытаетесь выйти из NSInteger, как если бы у него была известная длина. Точно так же вы должны быть осторожны при отправке их переменным или аргументам, которые вводятся как ints, так как вы можете потерять некоторую точность в процессе.

в целом, если вы не ожидаете, чтобы иметь сотни тысяч из них в памяти сразу, проще использовать NSInteger, чем постоянно беспокоиться о разнице между ними.


в настоящее время (сентябрь 2014) я бы рекомендовал использовать NSInteger/CGFloat при взаимодействии с iOS API и т. д., Если вы также создаете свое приложение для arm64. Это потому, что вы, вероятно, получите неожиданные результаты при использовании float, long и int типы.

пример: FLOAT / DOUBLE vs 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 на основе компиляции/выполнения устоячивое.


на iOS в настоящее время не имеет значения, используете ли вы int или NSInteger. Это будет иметь большее значение, если / когда iOS перейдет на 64-бит.

проще говоря, NSIntegerС ints в 32-битном коде (и, следовательно, 32-битный длинный) и longs на 64-разрядный код (longв 64-битный код в 64-разрядный, а 32-разрядного в 32-разрядный код). Наиболее вероятная причина использования NSInteger вместо long не нарушать существующий 32-битный код (который использует ints).

CGFloat имеет ту же проблему: on 32-бит (по крайней мере, на OS X), это float; на 64-битном, это double.

обновление: С введением iPhone 5s, iPad Air, iPad Mini с Retina и iOS 7 Теперь вы можете создавать 64-битный код на iOS.

обновление 2: также, используя NSIntegers помогает в совместимости Swift-кода.


int = 4 байта (фиксированный независимо от размера архитектора) NSInteger = зависит от размера архитектора (например, для 4 byte architect = 4 byte nsinteger size)