什么时候使用NSInteger和int

当为iOS开发时,我应该使用NSInteger vs. int ?我在苹果示例代码中看到,他们在将值作为参数传递给函数或从函数返回值时使用NSInteger(或NSUInteger)。

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

但在函数中,它们只是使用int来跟踪值

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


int something;
something += somethingElseThatsAnInt;
...

我已经读到(被告知),NSInteger是一种在64位或32位环境中引用整数的安全方法,那么为什么要使用int呢?

136961 次浏览

当你不知道你的代码可能运行在什么样的处理器架构上时,你通常会使用NSInteger,所以出于某种原因,你可能想要最大的整数类型,在32位系统上它只是int,而在64位系统上它是long

我坚持使用NSInteger而不是int/long,除非你特别需要它们。

NSInteger/NSUInteger被定义为这些类型之一的*动态typedef,它们的定义如下:

#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

关于这些类型的正确格式说明符,请参见字符串编程指南的平台依赖的部分

如果你深入研究NSInteger的实现:

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

简单地说,NSInteger类型定义为你做了一个步骤:如果架构是32位,它使用int,如果架构是64位,它使用long。使用NSInteger,你不需要担心程序运行的架构。

OS X是“LP64”。这意味着:

int总是32位的。

long long总是64位的。

NSIntegerlong总是指针大小。这意味着它们在32位系统上是32位,在64位系统上是64位。

NSInteger存在的原因是因为许多遗留api错误地使用int而不是long来保存指针大小的变量,这意味着api必须在64位版本中从int更改为long。换句话说,API将具有不同的函数签名,这取决于您是为32位体系结构还是64位体系结构编译。NSInteger打算用这些遗留api来掩盖这个问题。

在新代码中,如果需要32位变量,则使用int;如果需要64位整数,则使用long long;如果需要指针大小的变量,则使用longNSInteger

为什么要使用int呢?

Apple使用int是因为对于循环控制变量(仅用于控制循环迭代),int数据类型很好,无论是数据类型大小还是它可以为循环保存的值。对于循环控制变量,即使是16位的int大多数时候也可以。

Apple将NSInteger用于函数返回值或函数参数因为在这种情况下,数据类型[大小]很重要,因为你使用函数所做的是与其他程序或其他代码段通信/传递数据;在你的问题中看到什么时候我应该使用NSInteger vs int?的答案…

他们[Apple]使用NSInteger(或NSUInteger) 当传递一个值时作为一个

.参数从函数或者返回一个值转换为函数

在iOS上,目前使用intNSInteger并不重要。如果iOS转向64位,这将变得更加重要。

简单地说,__abc0是32位代码中的__abc1(因此是32位长)和64位代码中的__abc2(64位代码中的__abc2是64位宽,但32位代码中的32位)。使用NSInteger而不是long最有可能的原因是不破坏现有的32位代码(使用__abc1)。

CGFloat有同样的问题:在32位(至少在OS X上)上,它是float;在64位上,它是double

随着iPhone 5s、iPad Air、iPad Mini Retina和iOS 7的推出,你现在可以在iOS上构建64位代码了。

此外,使用NSIntegers有助于Swift代码的互操作性。

你应该使用NSInteger,如果你需要将它们与常量值进行比较,如NSNotFound或NSIntegerMax,因为这些值在32位和64位系统上是不同的,所以索引值,计数等:使用NSInteger或NSUInteger。

在大多数情况下使用NSInteger没有什么坏处,除了它占用两倍的内存。内存的影响非常小,但如果在任何时候都有大量的数字浮动,那么使用int型可能会有所不同。

如果你确实使用NSInteger或NSUInteger,当使用格式化字符串时,你会想要将它们转换为长整数或无符号长整数,因为如果你尝试注销一个NSInteger,就像它有一个已知的长度一样,Xcode的新特性会返回一个警告。在将它们发送给int类型的变量或参数时,也应该同样小心,因为在这个过程中可能会失去一些精度。

总的来说,如果你不希望在内存中同时有成千上万个NSInteger,那么使用NSInteger比不断担心两者之间的差异要容易得多。

截至目前(2014年9月),如果你也在为arm64构建应用程序,我建议在与iOS API的交互时使用NSInteger/CGFloat。 这是因为当你使用floatlongint类型时,你可能会得到意想不到的结果

例子: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位值。当需要一个32位值时返回一个64位值将会给出一个意外的行高

你可以使用CGFloat类型来解决这个问题

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

该类型表示32位环境中的32位float和64位环境中的64位double。因此,在使用此类型时,无论编译/运行时环境如何,方法总是会接收到预期的类型。

对于期望整数的方法也是如此。 这样的方法在32位环境中需要32位的int值,在64位环境中需要64位的long值。你可以通过使用类型NSInteger来解决这种情况,它作为基于编译/运行时环境的intlong

int = 4字节(与架构器大小无关) NSInteger =取决于架构师的大小(例如:(4字节架构师= 4字节NSInteger size)