在为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?
当您不知道代码可以在哪种处理器体系结构上运行时,通常需要使用NSInteger,因此出于某种原因,您可能需要最大可能的整数类型,在32位系统上,该整数类型仅为int,而在64位系统上,它是long。
除非您特别需要,否则我会坚持使用NSInteger代替int / long。
NSInteger / NSUInteger被定义为以下类型之一的* dynamic 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
关于应为每种类型使用的正确格式说明符,请参阅《字符串编程指南》中有关平台依赖项的部分
另外,除非您特别需要int或long int,否则我会说最好使用NSInteger。
因此,同时使用这两种方法的苹果示例代码毫无意义,因为它实际上没有获得NSInteger的好处吗?
在这种特定情况下,@ Shizam表示使用int完全可以,因为您知道上限是多少。 (something)-如果您不知道它是什么,那么使用NSInteger更有意义。
@Shizam另外,返回NSInteger通常是最好的,因为该数字可能相差很大。
@Jacob Relkin因此,使用NSInteger的原因有两个,它可以解决32/64位系统,并且可以将long倍增而不是int?我想我的意思是,如果NSInteger这么好,为什么除了易于输入之外,还会使用int?
@Shizam使用int甚至可能更适合long。也许您知道它不会超出某个范围,因此认为仅使用int会更节省内存。
啊,是的,记忆总是回到那个地方。好的,我想我现在就何时使用NSInteger与int有了一个很好的决策矩阵。
@Shizam:使用int的最佳原因是因为您正在使用使用int的API。 Cocoa之外很少使用NSInteger,因此,如果您使用其他库,它将希望以int而不是NSIntegers进行对话。
我不同意这个答案。我唯一要使用的NSInteger是将值传递给指定它的API或从中传递值。除此之外,它比int或long没有优势。至少对于int或long而言,您知道在printf或类似语句中使用哪种格式说明符。
如果在64b系统中工作时需要存储很长的时间并使用NSInteger,而其他用户使用32b系统会发生什么情况呢?您不会注意到失败,但是用户会注意到。
这是倒退。除非您有特殊原因,否则始终使用int。使用平台特定的简单整数定义没有任何作用,但会使您的代码更难阅读。
为什么要完全使用int?
Apple使用int是因为对于循环控制变量(仅用于控制循环迭代),int数据类型很好,无论是数据类型大小还是可以为循环保留的值。此处无需依赖平台的数据类型。对于循环控制变量,即使在大多数情况下,甚至16位int也会起作用。
Apple使用NSInteger作为函数返回值或函数自变量,因为在这种情况下,数据类型[size]很重要,因为您对函数所做的工作是与其他程序或其他代码段通信/传递数据。看到我何时应该使用NSInteger vs int的答案?在你自己的问题上...
they [Apple] use NSInteger (or NSUInteger) when passing a value as an
argument to a function or returning a value from a function.
OS X是" LP64"。这意味着:
int始终为32位。
long long始终为64位。
NSInteger和long始终为指针大小。这意味着它们在32位系统上为32位,在64位系统上为64位。
存在NSInteger的原因是因为许多旧版API错误地使用int而不是long来保存指针大小的变量,这意味着API必须在其64位版本中从int更改为long。换句话说,根据您是针对32位还是64位体系结构进行编译,API的功能签名将有所不同。 NSInteger打算使用这些旧版API掩盖此问题。
在新代码中,如果需要32位变量,请使用int;如果需要64位整数,请使用long long;如果需要指针大小的变量,请使用long或NSInteger。
历史已经存在,但建议却很糟糕。如果需要32位变量,请使用int32_t。如果需要64位整数,请使用int64_t。如果需要指针大小的变量,请使用intptr_t。
Stephen,您的建议是永远不要使用int,long或NSInteger?
不,我的建议是,如果您需要已知固定大小的整数类型,请不要使用它们。为此存在类型。
Stephen,我的回答是回答"何时使用NSInteger vs int"这个问题,而不是"什么是32位整数的跨平台类型名称"。如果有人试图在NSInteger和int之间做出选择,他们可能会知道他们在支持的平台上有多大。
还要注意,LP64不能保证long long为64位。 LP64平台可以选择使long long为128位整数。
这个答案对Lion仍然有效吗?
@ digital-robot绝对。
如果您深入研究NSInteger的实现:
#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif
简而言之,NSInteger typedef为您执行了一个步骤:如果体系结构是32位,则使用int;如果体系结构是64位,则使用long。使用NSInteger,您无需担心程序正在运行的体系结构。
您确实需要担心,因为NSInteger的正确格式说明符取决于体系结构。
根据Apple手册,最简单的方法是将值转换为最大的数字类型long long。因此,所有数字类型都将使用相同的类型说明符。
现在,最简单的格式化方法是将它们装箱-NSLog("%@", @(1123));
您还可以投射它:NSLog("%li", (long)theNSInteger);
演员让我伤心
从目前(2014年9月)开始,如果您还为arm64构建应用程序,则建议在与iOS API等交互时使用NSInteger/CGFloat。
这是因为当使用float,long和int类型时,您可能会得到意外的结果。
示例:浮点/双点与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来解决这种情况,该类型基于编译/运行时环境用作int或long。
如果我知道这个特定的变量值不能包含大数值怎么办,因此我希望使用int。它在64位环境中都能正常工作吗?我认为也应该这样做,因为我还没有看到这样的for循环:for(int i = 0; i <10; i ++)不管在什么环境下运行,都会做任何错误的行为。
@Chanchal Raj只要没有强制转换或转换为其他类型或涉及该变量的第三方类和方法的使用/重写,可以使用int代替NSInteger。
如果需要将它们与常量值(例如NSNotFound或NSIntegerMax)进行比较,则应使用NSIntegers,因为这些值在32位和64位系统上会有所不同,因此索引值,计数等类似:请使用NSInteger或NSUInteger。
在大多数情况下,使用NSInteger不会造成任何伤害,只是它占用的内存是原来的两倍。内存影响很小,但是如果您一次有大量的数字在浮动,那么使用整数可能会有所不同。
如果您确实使用NSInteger或NSUInteger,则在使用格式字符串时,您将希望将它们转换为长整数或无符号长整数,因为如果您尝试注销NSInteger时就好像它具有已知长度,则新的Xcode功能会返回警告。同样,将它们发送到类型为int的变量或参数时,也应小心,因为您可能会在过程中失去一些精度。
总的来说,如果您不希望一次存储数十万个内存,那么使用NSInteger会比不断担心两者之间的差异要容易得多。
在iOS上,当前使用int还是NSInteger都无关紧要。如果/当iOS移至64位时,这将更为重要。
简而言之,在32位代码中,NSInteger是int(因此是32位长),在64位代码上是long(64位代码中的long是64位宽) ,但使用32位代码中的32位)。使用NSInteger而不是long的最可能的原因是不中断现有的32位代码(使用int s)。
CGFloat具有相同的问题:在32位(至少在OS X上)是float;在64位上,它是double。
更新:随着iPhone 5s,iPad Air,带Retina的iPad Mini和iOS 7的推出,您现在可以在iOS上构建64位代码。
更新2:此外,使用NSInteger有助于Swift代码互操作性。
int = 4字节(固定大小,与架构师无关)
NSInteger =取决于架构师的大小(例如4字节架构师= 4字节NSInteger大小)