Когда я должен использовать 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
?
Обычно вы хотите использовать 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
Что касается правильного спецификатора формата, который вы должны использовать для каждого из этих типов, см. раздел Руководство по программированию строк по зависимостям платформы
Зачем использовать int
вообще?
Apple использует int
, потому что для переменной управления циклом (которая используется только для управления итерациями цикла) int
тип данных в порядке, как в размере данных, так и в значениях, которые он может удерживать для вашего цикла. Здесь нет необходимости в зависимом от платформы типе данных. Для переменной управления циклом большую часть времени будет выполнять даже 16-разрядный int
.
Apple использует NSInteger
для возвращаемого значения функции или для аргумента функции , потому что в этом случае тип данных [размер] имеет значение, потому что то, что вы делаете с функцией, это передача/передача данных с помощью других программ или других фрагментов кода; см. ответ "Когда я должен использовать NSInteger vs 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
, если вам нужна переменная размера указателя.
int32_t
. Если вам нужно 64-битное целое число, используйте int64_t
. Если вам нужна переменная размером с указатель, используйте intptr_t
.
Если вы вникнете в реализацию NSInteger:
#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif
Просто команда typedef NSInteger делает для вас шаг: если архитектура 32-разрядная, она использует int
, если она 64-разрядная, она использует long
. Используя NSInteger, вам не нужно беспокоиться о архитектуре, в которой работает программа.
long long
. Таким образом, все числовые типы будут использовать один и тот же спецификатор типа.
В настоящее время (сентябрь 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
на основе среды компиляции/времени выполнения.
Вы должны использовать NSIntegers, если вам нужно сравнить их с постоянными значениями, такими как NSNotFound или NSIntegerMax, поскольку эти значения будут отличаться в 32-битных и 64-битных системах, поэтому значения индекса, подсчеты и тому подобное: используйте NSInteger или NSUInteger.
Не больно использовать NSInteger в большинстве случаев, за исключением того, что он занимает вдвое больше памяти. Влияние памяти очень мало, но если у вас есть огромное количество чисел, плавающих вокруг в любой момент времени, это может иметь значение для использования ints.
Если вы используете NSInteger или NSUInteger, вам нужно будет наложить их на длинные целые числа или беззнаковые длинные целые числа при использовании строк формата, поскольку новая функция Xcode возвращает предупреждение, если вы попытаетесь выйти из NSInteger, как если бы он знал длина. Аналогичным образом вы должны быть осторожны при отправке их в переменные или аргументы, которые вводятся как int, поскольку вы можете потерять некоторую точность в процессе.
В целом, если вы не ожидаете иметь сотни тысяч из них в памяти сразу, проще использовать NSInteger, чем постоянно беспокоиться о различии между ними.
В 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.
int = 4 байт (фиксированный независимо размер архитектор) NSInteger = зависит от размера архитектора (например, для 4-байтного архитектора = 4 байта размера NSInteger)