Когда использовать 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с ints в 32-битном коде (и, следовательно, в 32-битном коде) и longна 64-битном коде (longs в 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: также с использованием NSIntegers помогает с совместимостью кода 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)

Другие вопросы по тегам