Когда использовать NSInteger против Int - PullRequest
337 голосов
/ 15 декабря 2010

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

314 голосов
/ 15 декабря 2010

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

Я бы остановился на использовании NSInteger вместо int / long, если только вам это не требуется.

NSInteger / NSUInteger определены как * динамические typedef* относится к одному из этих типов, и они определены следующим образом:

#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

Что касается правильного спецификатора формата, который вы должны использовать для каждого из этих типов, см. раздел Руководство по программированию строкиЗависимости платформы

44 голосов
/ 16 марта 2011

Зачем вообще использовать int?

Apple использует int, потому что для переменной управления циклом (которая используется только для управления итерациями цикла) int тип данныххорошо, как по размеру типа данных, так и по значениям, которые он может содержать для вашего цикла. Здесь не требуется тип данных, зависящий от платформы. Для переменной управления циклом большую часть времени будет выполнять даже 16-битная int.

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

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

31 голосов
/ 15 декабря 2010

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, если вам нужна переменная размером с указатель.

26 голосов
/ 15 декабря 2010

Если вы углубитесь в реализацию NSInteger:

#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif

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

9 голосов
/ 05 сентября 2014

На данный момент (сентябрь 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 на основе среды compile / runtime.

9 голосов
/ 14 марта 2014

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

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

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

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

9 голосов
/ 14 января 2013

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

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

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

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

Обновление 2: Кроме того, использование NSInteger s помогает в совместимости кода Swift.

0 голосов
/ 17 января 2017

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

...