Коли використовувати 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.