Kapan menggunakan NSInteger vs. int

344

Kapan saya harus menggunakan NSIntegervs. int saat mengembangkan untuk iOS? Saya melihat dalam kode sampel Apple yang mereka gunakan NSInteger(atau NSUInteger) ketika meneruskan nilai sebagai argumen ke suatu fungsi atau mengembalikan nilai dari suatu fungsi.

- (NSInteger)someFunc;...
- (void)someFuncWithInt:(NSInteger)value;...

Tetapi dalam suatu fungsi mereka hanya menggunakan intuntuk melacak nilai

for (int i; i < something; i++)
...

int something;
something += somethingElseThatsAnInt;
...

Saya telah membaca (diberi tahu) bahwa NSIntegerini adalah cara yang aman untuk mereferensikan integer baik dalam lingkungan 64-bit atau 32-bit jadi mengapa menggunakan intsama sekali?

Shizam
sumber

Jawaban:

322

Anda biasanya ingin menggunakan NSIntegerketika Anda tidak tahu apa jenis arsitektur prosesor kode Anda mungkin berjalan, jadi Anda mungkin karena beberapa alasan ingin jenis integer terbesar, yang pada sistem 32 bit hanya sebuah int, sedangkan pada 64-bit sistem itu long.

Saya akan tetap menggunakan NSIntegerbukan int/ longkecuali jika Anda secara khusus membutuhkannya.

NSInteger/ NSUIntegerdidefinisikan sebagai * dinamis typedef* untuk salah satu dari jenis ini, dan mereka didefinisikan seperti ini:

#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

Berkenaan dengan penentu format yang benar yang harus Anda gunakan untuk masing-masing jenis ini, lihat bagian Panduan Pemrograman String tentang Ketergantungan Platform

Jacob Relkin
sumber
4
Selain itu, saya akan mengatakan yang terbaik adalah menggunakan NSInteger kecuali Anda secara khusus memerlukan int atau int panjang.
v01d
4
@ Shizam Ada kemungkinan bahwa menggunakan intakan lebih cocok bahkan long. Mungkin Anda tahu bahwa itu tidak akan melebihi rentang tertentu, dan karena itu berpikir itu akan lebih efisien menggunakan memori saja int.
Jacob Relkin
58
Saya tidak setuju dengan jawaban ini. Satu-satunya hal yang akan saya gunakan NSIntegeradalah memberikan nilai ke dan dari API yang menentukannya. Selain itu tidak memiliki keunggulan dibandingkan int atau panjang. Setidaknya dengan int atau lama Anda tahu penentu format apa yang harus digunakan dalam printf atau pernyataan serupa.
JeremyP
3
Apa yang terjadi jika Anda perlu menyimpan lama dan Anda menggunakan NSInteger saat Anda bekerja di sistem 64b tetapi pengguna lain menggunakan sistem 32b? Anda tidak akan melihat kegagalannya tetapi pengguna akan melihatnya.
arielcamus
14
Ini mundur. Selalu gunakan int kecuali Anda memiliki alasan spesifik sebaliknya. Menggunakan definisi spesifik platform untuk bilangan bulat sederhana tidak membuat apa pun selain membuat kode Anda lebih sulit dibaca.
Glenn Maynard
44

Kenapa pakai intsama sekali?

Apple menggunakan intkarena untuk variabel kontrol loop (yang hanya digunakan untuk mengontrol iterasi loop) intdatatype baik-baik saja, baik dalam ukuran datatype dan dalam nilai-nilai yang dapat disimpan untuk loop Anda. Tidak perlu untuk tipe data platform bergantung di sini. Untuk variabel kontrol loop bahkan 16-bit intakan melakukan sebagian besar waktu.

Apple menggunakan NSIntegernilai pengembalian fungsi atau argumen fungsi karena dalam hal ini datatype [size] penting , karena apa yang Anda lakukan dengan suatu fungsi adalah mengkomunikasikan / meneruskan data dengan program lain atau dengan potongan kode lainnya; lihat jawaban untuk Kapan saya harus menggunakan NSInteger vs int?dalam pertanyaan Anda sendiri ...

mereka [Apple] menggunakan NSInteger (atau NSUInteger) ketika meneruskan nilai sebagai argumen ke suatu fungsi atau mengembalikan nilai dari suatu fungsi.

Hanya kamu
sumber
32

OS X adalah "LP64". Ini berarti:

int selalu 32-bit.

long long selalu 64-bit.

NSIntegerdan longselalu berukuran pointer. Itu berarti mereka 32-bit pada sistem 32-bit, dan 64 bit pada sistem 64-bit.

Alasan NSInteger ada adalah karena banyak API lawas yang digunakan secara salah intalih-alih longmenahan variabel ukuran pointer, yang berarti bahwa API harus berubah dari intke longdalam versi 64-bit mereka. Dengan kata lain, API akan memiliki tanda tangan fungsi yang berbeda tergantung pada apakah Anda mengkompilasi arsitektur 32-bit atau 64-bit. NSIntegerbermaksud untuk menutupi masalah ini dengan API lawas ini.

Dalam kode baru Anda, gunakan intjika Anda memerlukan variabel 32-bit, long longjika Anda membutuhkan integer 64-bit, dan longatau NSIntegerjika Anda memerlukan variabel berukuran pointer.

Darren
sumber
25
Sejarahnya tepat, tetapi nasihatnya mengerikan. Jika Anda memerlukan penggunaan variabel 32-bit int32_t. Jika Anda membutuhkan penggunaan integer 64-bit int64_t. Jika Anda membutuhkan penggunaan variabel berukuran pointer intptr_t.
Stephen Canon
5
Stephen, saran Anda adalah jangan pernah menggunakan int, long, atau NSInteger?
Darren
7
Tidak, saran saya adalah jangan pernah menggunakannya jika Anda memerlukan tipe bilangan bulat ukuran tetap yang diketahui. The <stdint.h>jenis ada untuk tujuan itu.
Stephen Canon
3
Stephen, jawaban saya adalah menjawab pertanyaan "Kapan harus menggunakan NSInteger vs int", bukan "apa jenis nama lintas-platform dari integer 32-bit". Jika seseorang mencoba untuk memutuskan antara NSInteger dan int mereka mungkin juga tahu seberapa besar mereka pada platform yang mereka dukung.
Darren
1
Perhatikan juga bahwa LP64itu tidak menjamin bahwa itu long longadalah 64 bit. Sebuah LP64platform dapat memilih untuk memiliki long longinteger 128 bit.
Stephen Canon
26

Jika Anda menggali implementasi NSInteger:

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

Sederhananya, typedef NSInteger melakukan langkah untuk Anda: jika arsitekturnya 32-bit, ia menggunakan int, jika 64-bit, ia menggunakan long. Menggunakan NSInteger, Anda tidak perlu khawatir tentang arsitektur yang sedang dijalankan oleh program.

Evan Mulawski
sumber
14
Anda perlu khawatir, karena specifier format yang benar untuk NSInteger bergantung pada arsitektur.
JeremyP
Cara paling sederhana menurut manual Apple adalah memberikan nilai ke tipe numerik terbesar long long. Jadi semua tipe numerik akan menggunakan specifier tipe yang sama.
Eonil
6
Sekarang cara paling sederhana untuk memformat hanya tinju mereka -NSLog("%@", @(1123));
Eonil
1
Anda juga dapat melemparkannya:NSLog("%li", (long)theNSInteger);
Daniel
casting membuatku sedih
tomalbrc
9

Anda harus menggunakan NSIntegers jika Anda perlu membandingkannya dengan nilai konstan seperti NSNotFound atau NSIntegerMax, karena nilai-nilai ini akan berbeda pada sistem 32-bit dan 64-bit, sehingga nilai indeks, jumlah dan sejenisnya: gunakan NSInteger atau NSUInteger.

Tidak ada salahnya menggunakan NSInteger di sebagian besar keadaan, kecuali bahwa itu memakan memori dua kali lebih banyak. Imbas memori sangat kecil, tetapi jika Anda memiliki sejumlah besar angka yang mengambang pada satu waktu, itu mungkin membuat perbedaan untuk menggunakan int.

Jika Anda DO menggunakan NSInteger atau NSUInteger, Anda akan ingin memasukkannya ke dalam bilangan bulat panjang atau bilangan bulat tak bertanda saat menggunakan string format, karena fitur Xcode baru mengembalikan peringatan jika Anda mencoba dan keluar NSInteger seolah-olah memiliki panjang yang diketahui. Anda juga harus berhati-hati saat mengirimnya ke variabel atau argumen yang diketik sebagai int, karena Anda mungkin kehilangan ketepatan dalam prosesnya.

Secara keseluruhan, jika Anda tidak berharap memiliki ratusan ribu memori sekaligus, lebih mudah menggunakan NSInteger daripada terus-menerus khawatir tentang perbedaan di antara keduanya.

Abu
sumber
9

Sampai saat ini (September 2014) saya akan merekomendasikan menggunakan NSInteger/CGFloatketika berinteraksi dengan iOS API dll jika Anda juga membangun aplikasi Anda untuk arm64. Ini karena Anda kemungkinan akan mendapatkan hasil yang tidak terduga ketika Anda menggunakan float, longdanint mengetik.

CONTOH: FLOAT / GANDA vs CGFLOAT

Sebagai contoh, kami menggunakan metode delegasi UITableView tableView:heightForRowAtIndexPath:.

Dalam aplikasi 32-bit saja itu akan berfungsi dengan baik jika ditulis seperti ini:

-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 44;
}

floatadalah nilai 32-bit dan 44 yang Anda kembalikan adalah nilai 32-bit. Namun, jika kita mengkompilasi / menjalankan bagian kode yang sama dalam arsitektur arm64 64-bit, 44 akan menjadi nilai 64-bit. Mengembalikan nilai 64-bit ketika nilai 32-bit diharapkan akan memberikan tinggi baris yang tidak terduga.

Anda dapat mengatasi masalah ini dengan menggunakan CGFloattipe

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 44;
}

Tipe ini mewakili 32-bit floatdalam lingkungan 32-bit dan 64-bit doubledalam lingkungan 64-bit. Karenanya saat menggunakan tipe ini metode akan selalu menerima tipe yang diharapkan terlepas dari lingkungan kompilasi / runtime.

Hal yang sama berlaku untuk metode yang mengharapkan bilangan bulat. Metode seperti itu akan mengharapkan nilai 32-bit intdalam lingkungan 32-bit dan 64-bit longdalam lingkungan 64-bit. Anda dapat menyelesaikan kasus ini dengan menggunakan tipe NSIntegeryang berfungsi sebagai intatau longberdasarkan pada kompilasi / runtime environmentemnt.

Leon Lucardie
sumber
Bagaimana jika saya tahu nilai variabel khusus ini tidak dapat berisi nilai angka besar dan saya ingin menggunakan int. Apakah akan berfungsi dengan baik dalam lingkungan 64-bit. Saya pikir itu juga harus, karena saya belum melihat untuk loop seperti ini: for (int i = 0; i <10; i ++) melakukan perilaku yang salah terlepas dari lingkungan yang dijalankan.
Chanchal Raj
@Chanchal Raj Selama tidak ada casting atau konversi ke tipe lain atau penggunaan / pengesampingan kelas pihak ketiga dan metode yang melibatkan variabel itu, menggunakan int bukan NSInteger akan baik-baik saja.
Leon Lucardie
9

Di iOS, saat ini tidak masalah jika Anda menggunakan intatau NSInteger. Akan lebih penting jika / ketika iOS pindah ke 64-bit.

Sederhananya, NSIntegers adalah intdalam kode 32-bit (dan dengan demikian panjangnya 32-bit) dan longs pada kode 64-bit ( longs dalam kode 64-bit lebar 64-bit, tetapi 32-bit dalam kode 32-bit). Alasan yang paling mungkin untuk menggunakan NSIntegeralih-alih longadalah untuk tidak merusak kode 32-bit yang ada (yang menggunakan ints).

CGFloatmemiliki masalah yang sama: pada 32-bit (setidaknya pada OS X), itu float; pada 64-bit, itu double.

Pembaruan: Dengan diperkenalkannya iPhone 5s, iPad Air, iPad Mini dengan Retina, dan iOS 7, kini Anda dapat membuat kode 64-bit di iOS.

Pembaruan 2: Juga, menggunakan NSIntegers membantu dengan interoperabilitas kode Swift.

MaddTheSane
sumber
0

int = 4 byte (ukuran tetap terlepas dari arsitek) NSInteger = tergantung pada ukuran arsitek (misalnya untuk arsitek 4 byte = 4 byte ukuran NSInteger)

Ankit garg
sumber