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

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


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

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

int something;
something += somethingElseThatsAnInt;
...


我已经读过(被告知)NSInteger是一种安全的引用整数的方法一个64位或32位环境,为什么要完全使用int

#1 楼

当您不知道代码可以在哪种处理器体系结构上运行时,通常需要使用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


关于每种类型应使用的正确格式说明符,请参见《字符串编程指南》中有关平台依赖项的部分

评论


另外,除非您特别要求int或long int,否则我将说最好使用NSInteger。

– v01d
2010-12-14 23:08

@Shizam使用int可能更适合长时间使用。也许您知道它不会超出某个范围,因此认为仅使用int会更节省内存。

–雅各布·勒金(Jacob Relkin)
2010-12-14 23:27

我不同意这个答案。我唯一要使用NSInteger的东西是在指定它的API之间传递值。除此之外,它比int或long没有优势。至少对于int或long而言,您知道在printf或类似语句中使用哪种格式说明符。

– JeremyP
2010-12-15 9:13

如果在64b系统中工作时需要存储很长的时间并使用NSInteger,而其他用户使用32b系统会发生什么情况呢?您不会注意到失败,但用户会注意到。

–arielcamus
2012年9月10日17:08

这是倒退。除非您有特殊原因,否则始终使用int。使用特定于平台的简单整数定义没有任何作用,但会使您的代码更难阅读。

–格伦·梅纳德(Glenn Maynard)
13年2月20日在0:31

#2 楼

为什么要完全使用int

Apple使用int是因为对于循环控制变量(仅用于控制循环迭代),int数据类型在数据类型大小和它可以容纳的值方面都很好为您的循环。此处无需依赖平台的数据类型。对于循环控制变量,即使是16位的int在大多数情况下也可用。

Apple使用NSInteger作为函数返回值或函数参数,因为在这种情况下,数据类型[size]很重要,因为您正在执行的功能是与其他程序或其他代码通信/传递数据;看到我何时应该使用NSInteger vs int的答案?在您自己的问题中...


[Apple]在将值作为
参数传递给函数或从函数返回值时,他们[Apple]使用NSInteger(或NSUInteger) 。


#3 楼

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

int始终为32位。

long long始终为64位。

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

之所以存在NSInteger的原因是,因为许多旧版API错误地使用了int而不是long来保存指针-大小的变量,这意味着API必须在其64位版本中从int更改为long。换句话说,根据您是针对32位还是64位体系结构进行编译,API的功能签名将有所不同。 NSInteger打算使用这些旧版API掩盖此问题。

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

评论


历史已经存在,但建议却很糟糕。如果需要32位变量,请使用int32_t。如果需要64位整数,请使用int64_t。如果需要指针大小的变量,请使用intptr_t。

–斯蒂芬·佳能(Stephen Canon)
2010-12-14 23:54

Stephen,您的建议是永远不要使用int,long或NSInteger?

–达伦
2010-12-14 23:58

不,我的建议是,如果需要已知固定大小的整数类型,请不要使用它们。为此,存在类型。

–斯蒂芬·佳能(Stephen Canon)
2010-12-15在0:09



Stephen,我的回答是回答“何时使用NSInteger vs int”这个问题,而不是“什么是32位整数的跨平台类型名称”。如果有人试图在NSInteger和int之间做出选择,他们可能会知道他们在支持的平台上有多大。

–达伦
2010-12-15在1:01



还要注意,LP64不保证long long是64位。 LP64平台可以选择将long长为128位整数。

–斯蒂芬·佳能(Stephen Canon)
2010-12-15在2:59

#4 楼

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

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


简单地,NSInteger typedef会为您执行一个步骤:如果体系结构是32位的,则使用int,如果64位,它使用long。使用NSInteger,您无需担心程序在其上运行的体系结构。

评论


您确实需要担心,因为NSInteger的正确格式说明符取决于体系结构。

– JeremyP
2010-12-15 9:15

根据Apple手册,最简单的方法是将long值转换为最大的数字类型。因此,所有数字类型都将使用相同的类型说明符。

–尼尔
2012年7月21日在19:24

现在,最简单的格式化方法是将它们装箱-NSLog(“%@”,@(1123));

–尼尔
2013年9月21日在10:44

您还可以强制转换它:NSLog(“%li”,(long)theNSInteger);

–丹尼尔(Daniel)
15年3月16日在16:18

演员让我伤心

–tomalbrc
17年6月20日在18:26

#5 楼

如果需要将它们与NSNotFound或NSIntegerMax等常量值进行比较,则应使用NSIntegers,因为这些值在32位和64位系统上会有所不同,因此索引值,计数等:请使用NSInteger或NSUInteger。 />
在大多数情况下使用NSInteger并没有什么坏处,除了它占用两倍的内存。内存影响很小,但是如果您一次有大量的数字在浮动,那么使用int可能会有所不同。

如果您确实使用NSInteger或NSUInteger,您将希望在使用格式字符串时将其转换为长整数或无符号长整数,因为如果您尝试注销NSInteger时就好像它具有已知长度,则新的Xcode功能会返回警告。同样,在将它们发送到类型为int的变量或参数时,也应该小心,因为在过程中可能会失去一些精度。

总的来说,如果您不希望有数百个一次将数千个存储在内存中,使用NSInteger比不断担心两者之间的差异要容易得多。

#6 楼

在iOS上,当前使用int还是NSInteger都无关紧要。如果/当iOS移至64位时,这将变得更加重要。

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

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

更新:随着iPhone 5s,iPad Air,带有Retina的iPad Mini和iOS 7的推出,您现在可以在iOS上构建64位代码。 br />
更新2:同样,使用NSInteger s也有助于实现Swift代码的互操作性。

#7 楼

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

示例:FLOAT / DOUBLE与CGFLOAT

作为示例,我们采用UITableView委托方法tableView:heightForRowAtIndexPath:

仅在32位中在应用程序中,如果这样编写,将可以正常工作:

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


float是32位值,而返回的44是32位值。 br />但是,如果我们在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类型解决此问题,该类型基于编译/运行时环境用作NSIntegerint

评论


如果我知道这个特定变量的值不能包含大数值,那么我该使用int怎么办。它在64位环境中都能正常工作吗?我认为也应该这样做,因为我还没有看到像这样的for循环:for(int i = 0; i <10; i ++)不管在什么环境下运行,都会做任何错误的行为。

–Chanchal Raj
17年2月1日在8:51

@Chanchal Raj只要没有强制转换或转换为其他类型或涉及该变量的第三方类和方法的使用/重写,可以使用int代替NSInteger。

–莱昂·卢卡迪(Leon Lucardie)
17年6月13日在9:25



#8 楼

int = 4字节(无论架构师的大小如何固定)
NSInteger =取决于架构师的大小(例如,对于4字节的Architect = 4字节的NSInteger大小)