Коли використовувати NSInteger vs. int


344

Коли я повинен використовувати NSIntegervs. 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взагалі використовувати ?

Відповіді:


322

Зазвичай ви хочете використовувати, NSIntegerколи ви не знаєте, якою архітектурою процесора може працювати ваш код, тому, можливо, ви хочете, чомусь, захочете максимально можливого цілого типу, який у 32-бітових системах є просто an 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

Що стосується правильного специфікатора формату, який слід використовувати для кожного з цих типів, дивіться розділ Посібника для програмування рядків про залежність від платформи


4
Крім того, я б сказав, що найкраще використовувати NSInteger, якщо ви спеціально не вимагаєте int або long int.
v01d

4
@Shizam Цілком можливо, що використання "A" intкраще підходить навіть для "a" long. Можливо, ви знаєте, що це звичайно перевищує певний діапазон, і тому ви думаєте, що просто використовуватиме більшу пам'ять int.
Яків Релькін

58
Я не згоден з цією відповіддю. Єдине, для чого я би скористався, NSInteger- це передавання значень до та з API, який його визначає. Крім цього він не має переваги перед int або long. Принаймні, з int або long ви знаєте, які специфікатори формату використовувати в операторі printf або подібному.
ДжереміP

3
Що станеться, якщо вам потрібно довго зберігати та використовувати NSInteger під час роботи в системі 64b, але інший користувач використовує систему 32b? Ви не помітите помилку, але користувач буде.
arielcamus

14
Це назад. Завжди використовуйте int, якщо у вас немає конкретної причини іншого. Використання визначених для платформи визначених простих цілих чисел не робить нічого, окрім ускладнює читання вашого коду.
Гленн Мейнард

44

Навіщо використовувати intвзагалі?

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

Apple використовує NSIntegerдля функції повернення значення або для аргументу функції, оскільки в цьому випадку тип даних [розмір] має значення , оскільки те, що ви робите з функцією, - це передавання / передача даних з іншими програмами або з іншими фрагментами коду; див. відповідь на те, Коли я повинен використовувати NSInteger vs int? в самому вашому питанні ...

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


32

OS X - "LP64". Це означає що:

int завжди 32-бітний.

long long завжди 64-біт.

NSIntegerі longзавжди мають розмір вказівника. Це означає, що вони 32-бітові в 32-бітних системах і 64-бітні в 64-бітних системах.

Причина існування NSInteger полягає в тому, що багато застарілих API неправильно використовуються intзамість того, longщоб утримувати змінні розміру вказівника, що означало, що API довелося змінити з intна long64-бітні версії. Іншими словами, 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?
Даррен

7
Ні, моя порада ніколи не використовувати їх, якщо вам потрібен цілий тип відомого фіксованого розміру. Для цього <stdint.h>існують типи.
Стівен Канон

3
Стівен, моя відповідь була у відповідь на запитання "Коли використовувати NSInteger vs int", а не "яке назви крос-платформ 32-бітного цілого числа". Якщо хтось намагається вибрати між NSInteger та int, вони також можуть знати, наскільки вони великі на платформах, які вони підтримують.
Даррен

1
Зауважте також, що LP64це не гарантує long long64 біт. LP64Платформа може обрати , щоб long longбути 128 - бітове ціле.
Стівен Канон

26

Якщо ви скористаєтеся реалізацією NSInteger:

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

Просто, тип NSInteger typedef робить крок для вас: якщо архітектура є 32-розрядною, вона використовує int, якщо вона 64-бітна, вона використовує long. Використовуючи NSInteger, вам не потрібно турбуватися про архітектуру, на якій працює програма.


14
Вам потрібно хвилюватися, адже правильний специфікатор формату для NSInteger залежить від архітектури.
JeremyP

Згідно з посібником від Apple, найпростіший спосіб - це значення величини для найбільшого числового типу long long. Таким чином, всі числові типи використовуватимуть специфікатор одного типу.
Еоніл

6
Тепер найпростіший спосіб форматування - це просто боксувати їх -NSLog("%@", @(1123));
Eonil

1
Ви також можете це зробити:NSLog("%li", (long)theNSInteger);
Даніель

кастинг мене сумує
tomalbrc

9

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

Використовувати NSInteger у більшості випадків не завадить, за винятком того, що він займає вдвічі більше пам’яті. Вплив на пам'ять дуже малий, але якщо у вас в будь-який час плаває величезна кількість цифр, можливо, використання знаків Ints може змінити значення.

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

В цілому, якщо ви не розраховуєте мати сотні тисяч з них в пам'яті одразу, простіше використовувати NSInteger, ніж постійно турбуватися про різницю між ними.


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;
}

float32-бітове значення, а 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. Чи буде добре працювати як в 64-бітовому середовищі. Я думаю, що це теж повинно бути, оскільки я не бачив подібного циклу: for (int i = 0; i <10; i ++), що робить будь-яку неправильну поведінку, незалежно від середовища, в яке він працює.
Chanchal Raj,

@Chanchal Raj До тих пір, поки немає кастингу або перетворення на інші типи або використання / переопределення сторонніх класів і методів, що включають цю змінну, використання int замість NSInteger буде добре.
Леон Лукарді

9

На iOS наразі не має значення, використовуєте ви intчи NSInteger. Буде важливіше, якщо / коли iOS перейде на 64-бітні.

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

CGFloatмає таку ж проблему: для 32-розрядних (принаймні для OS X) це float; на 64-розрядному, це double.

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

Оновлення 2: Також використання NSIntegers допомагає при сумісності коду Swift.


0

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.