NSIntegerとintを使用する場合


344

NSIntegeriOS用に開発する場合、vs.intをいつ使用する必要がありますか?関数に引数として値を渡したり、関数から値を返したりするときに使用するNSInteger(またはNSUInteger)Appleサンプルコードを確認しました。

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

しかし、関数内ではint、値を追跡するために使用しています

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

int something;
something += somethingElseThatsAnInt;
...

私はNSInteger、64ビットまたは32ビット環境で整数を参照する安全な方法であると(言われました)読んだので、なぜ使用intするのですか?

回答:


322

通常NSInteger、コードが実行される可能性のあるプロセッサアーキテクチャの種類がわからない場合に使用します。そのため、何らかの理由で、32ビットシステムではint64ビット上で、可能な最大の整数型が必要になる場合があります。システムそれはlongです。

特に必要でない限りNSIntegerint/の代わりに使用longすることにします。

NSInteger/ NSUIntegertypedef、これらのタイプの1つに対して*動的* 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
さらに、特にintまたはlong intが必要な場合を除いて、NSIntegerを使用するのが最善です。
v01d 2010

4
@Shizamを使用したint方がにも適している可能性がありlongます。たぶんあなたはそれが特定の範囲を超えないことを知っているので、単純にを使用するほうがメモリ効率が良くなると思いますint
Jacob Relkin、2010

58
私はこの答えに同意しません。私が使用する唯一のものNSIntegerは、それを指定するAPIとの間で値を渡すことです。それ以外は、intやlongよりも優れています。少なくともintまたはlongがあれば、printfまたは同様のステートメントで使用するフォーマット指定子を知っています。
JeremyP 2010

3
longを格納する必要があり、64bシステムで作業しているときにNSIntegerを使用しているが、他のユーザーが32bシステムを使用している場合はどうなりますか?あなたは失敗に気づかないでしょうが、ユーザーは気づくでしょう。
arielcamus 2012

14
これは逆です。特に理由がない限り、常にintを使用してください。単純な整数にプラットフォーム固有の定義を使用しても、コードが読みにくくなります。
Glenn Maynard

44

なぜ使用intするのですか?

intループ制御変数(ループの反復を制御するためだけに使用される)のintデータ型は、データ型のサイズとループに保持できる値の両方で問題ないため、Appleが使用しています。ここでは、プラットフォームに依存するデータ型は必要ありません。ループ制御変数の場合、16ビットでintもほとんどの場合に実行されます。

AppleはNSInteger関数の戻り値または関数の引数に使用します。これは、この場合、データ型[サイズ]が重要になるためです。関数で実行しているのは、他のプログラムまたは他のコードとデータの通信/受け渡しを行うためです。NSIntegerとintをいつ使用する必要があるかについての回答を参照してくださいあなたの質問自体で...

関数にを引数として渡すときまたは関数から返すときに、[Apple]はNSInteger(またはNSUInteger)を使用します。


32

OS Xは「LP64」です。この意味は:

int 常に32ビットです。

long long は常に64ビットです。

NSIntegerそしてlong、常にポインタのサイズです。つまり、32ビットシステムでは32ビット、64ビットシステムでは64ビットです。

NSIntegerが存在する理由は、ポインタサイズの変数を保持するint代わりに多くのレガシーAPIが誤って使用されたためlongです。これは、APIを64ビットバージョンからintに変更する必要があったことを意味しlongます。つまり、32ビットと64ビットのどちらのアーキテクチャ向けにコンパイルするかによって、APIの関数シグネチャが異なります。 NSIntegerこれらのレガシーAPIでこの問題を隠すつもりです。

新しいコードではint、32ビット変数long longが必要な場合、64ビット整数が必要な場合、longまたはNSIntegerポインターサイズの変数が必要な場合に使用します。


25
歴史は順調ですが、アドバイスはひどいです。32ビット変数が必要な場合は、を使用してくださいint32_t。64ビット整数が必要な場合は、を使用してくださいint64_t。ポインタサイズの変数が必要な場合は、を使用してくださいintptr_t
スティーブンキャノン

5
スティーブン、あなたのアドバイスは、int、long、NSIntegerを決して使用しないことですか?
Darren

7
いいえ、既知の固定サイズの整数型が必要な場合は使用しないことをお勧めします。<stdint.h>タイプは、その目的のために存在します。
スティーブンキャノン、

3
スティーブン、私の答えは「32ビット整数のクロスプラットフォームタイプ名は何ですか」ではなく、「いつNSIntegerとintを使用するか」という質問に対する回答でした。誰かがNSIntegerとintの間で決定しようとしている場合、サポートしているプラ​​ットフォーム上での大きさを知っているかもしれません。
Darren

1
LP64それlong longが64ビットであることを保証しないことにも注意してください。LP64プラットフォームは持っていることを選択する可能性がlong long128ビットの整数です。
スティーブンキャノン、

26

NSIntegerの実装を掘り下げる場合:

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

簡単に言うと、NSInteger typedefがステップを実行します。アーキテクチャが32ビットの場合はを使用しint、64ビットの場合はを使用しlongます。NSIntegerを使用すると、プログラムが実行されているアーキテクチャについて心配する必要はありません。


14
NSIntegerの正しいフォーマット指定子はアーキテクチャに依存しているため、心配する必要はありません。
JeremyP 2010

Appleのマニュアルによると、最も簡単な方法は、最大の数値型に値をキャストすることlong longです。したがって、すべての数値型は同じ型指定子を使用します。
Eonil

6
今、フォーマットする最も簡単な方法は、それらをボックス化することですNSLog("%@", @(1123));
Eonil

1
キャストすることもできます:NSLog("%li", (long)theNSInteger);
Daniel

キャスティングは私を悲しくします
tomalbrc

9

NSNotFoundやNSIntegerMaxなどの定数値と比較する必要がある場合は、NSIntegersを使用する必要があります。これらの値は32ビットシステムと64ビットシステムで異なるため、インデックス値、カウントなど:NSIntegerまたはNSUIntegerを使用します。

2倍のメモリを消費することを除いて、ほとんどの状況でNSIntegerを使用しても害はありません。メモリへの影響は非常に小さいですが、一度に大量の数値が浮かんでいる場合、intを使用すると違いが生じる可能性があります。

NSIntegerまたはNSUIntegerを使用する場合は、フォーマット文字列を使用するときに、長整数または符号なし長整数にキャストする必要があります。これは、NSIntegerを既知の長さであるかのようにログアウトしようとすると、新しいXcode機能が警告を返すためです。int型の変数または引数に送信する場合も同様に注意する必要があります。これは、プロセスの精度が失われる可能性があるためです。

全体として、一度に数十万個がメモリにあると予想しない場合は、常に2つの違いを心配するよりもNSIntegerを使用する方が簡単です。


9

現在(2014年9月)現在NSInteger/CGFloat、arm64用のアプリもビルドしている場合は、iOS APIなどとやり取りするときに使用することをお勧めします。これはfloatlongintタイプを使用すると予期しない結果が生じる可能性があるためです。

例:FLOAT / DOUBLEとCGFLOAT

例として、UITableViewデリゲートメソッドを使用しtableView:heightForRowAtIndexPath:ます。

32ビットのみのアプリケーションでは、次のように記述されていれば正常に機能します。

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

float32ビット値であり、返される44は32ビット値です。ただし、これと同じコードを64ビットarm64アーキテクチャでコンパイル/実行すると、44は64ビット値になります。32ビット値が予想されるときに64ビット値を返すと、予期しない行の高さが得られます。

CGFloatタイプを使用してこの問題を解決できます

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

このタイプは、32 floatビット環境の32ビットおよび64ビットを表しますdoubleます。したがって、このタイプを使用する場合、コンパイル/ランタイム環境に関係なく、メソッドは常に期待されるタイプを受け取ります。

整数を期待するメソッドについても同様です。このようなメソッドは、32 intビット環境では32 ビット値を、64ビット環境では64 ビット値を期待しlongます。このケースは、コンパイル/ランタイム環境に基づいNSIntegerて、intまたはとして機能するタイプを使用して解決できlongます。


この特定の変数の値に大きな数値を含めることはできず、intを使用したい場合はどうすればよいでしょうか。64ビット環境の両方で正常に動作しますか。私は、このようなループのために見ていないとして、それはあまりにもすべきだと思う:。(; I <10; int型iは0を= I ++)のためにかかわらず、環境のいずれかの間違った行動をして、それがで実行される
チャンチャルラジ

@Chanchal Raj他の型へのキャストや変換、サードパーティのクラスの使用/オーバーライド、およびその変数を含むメソッドがない限り、NSIntegerの代わりにintを使用することで問題ありません。
Leon Lucardie 2017年

9

iOSでは、現在、intまたはを使用しても問題ありませんNSInteger。iOSが64ビットに移行する場合は、さらに重要になります。

簡単に言えば、NSIntegersはint32ビットコードのs(したがって32ビット長)でありlong、64ビットコードlongのs です(64ビットコードのsは64ビット幅ですが、32ビットコードでは32ビットです)。のNSInteger代わりにを使用する最も可能性の高い理由longは、既存の32ビットコード(ints を使用)を壊さないためです。

CGFloat同じ問題があります:32ビット(少なくともOS X)ではfloat、64ビットではdoubleです。

アップデート: iPhone 5s、iPad Air、iPad Mini with Retina、およびiOS 7の導入により、iOSで64ビットコードをビルドできるようになりました。

Update 2:また、NSIntegersを使用すると、Swiftコードの相互運用性が向上します。


0

int = 4バイト(アーキテクトのサイズに関係なく固定)NSInteger =アーキテクトのサイズに依存(例:4バイトアーキテクトの場合= 4バイトNSIntegerサイズ)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.