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

332

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

Теги:
types
nsinteger

8 ответов

316
Лучший ответ

Обычно вы хотите использовать NSInteger, когда вы не знаете, на какую процессорную архитектуру может работать ваш код, поэтому вы можете по какой-то причине захотеть максимально возможный тип int, который на 32-битных системах просто a int, а в 64-битной системе - a 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

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

  • 4
    Кроме того, я бы сказал, что лучше использовать NSInteger, если вам не требуется int или long int.
  • 0
    Таким образом, пример кода Apple, использующий оба, не имеет смысла, поскольку он эффективно не получает ни одного из преимуществ NSInteger?
Показать ещё 9 комментариев
43

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

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

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

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

29

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

  • 25
    История на месте, но совет ужасен. Если вам нужна 32-битная переменная, используйте int32_t . Если вам нужно 64-битное целое число, используйте int64_t . Если вам нужна переменная размером с указатель, используйте intptr_t .
  • 5
    Стивен, ваш совет: никогда не использовать int, long или NSInteger?
Показать ещё 5 комментариев
25

Если вы вникнете в реализацию NSInteger:

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

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

  • 14
    Вам нужно беспокоиться, потому что правильный спецификатор формата для NSInteger зависит от архитектуры.
  • 0
    Согласно руководству Apple, самый простой способ - привести значение к наибольшему числовому типу long long . Таким образом, все числовые типы будут использовать один и тот же спецификатор типа.
Показать ещё 3 комментария
9

В настоящее время (сентябрь 2014 года) я бы рекомендовал использовать NSInteger/CGFloat при взаимодействии с API iOS и т.д., если вы также создаете свое приложение для 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 на основе среды компиляции/времени выполнения.

  • 0
    Что если я знаю, что значение этой конкретной переменной не может содержать больших числовых значений, и поэтому я хочу использовать int. Будет ли это нормально работать как в 64-битной среде? Я думаю, что это также должно произойти, так как я не видел цикл for, подобный этому: for (int i = 0; i <10; i ++) делает неправильное поведение независимо от среды, в которой он запущен.
  • 0
    @Chanchal Raj До тех пор, пока нет преобразования или преобразования в другие типы или использования / переопределения сторонних классов и методов с этой переменной, использование int вместо NSInteger будет приемлемым.
9

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

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

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

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

9

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

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

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

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

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

0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню