ChatGPT解决这个技术问题 Extra ChatGPT

何时使用 NSInteger 与 int

在为 iOS 开发时,我应该何时使用 NSInteger 与 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 呢?


D
Dmitry

当您不知道您的代码可能在哪种处理器架构上运行时,您通常希望使用 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

关于您应该为每种类型使用的正确格式说明符,请参阅 String Programming Guide's section on Platform Dependencies


此外,我会说最好使用 NSInteger,除非您特别需要 int 或 long int。
@Shizam 使用int 可能更适合long。也许您知道它不会超过某个范围,因此认为简单地使用 int 会更节省内存。
我不同意这个答案。我唯一会使用 NSInteger 的是将值传入和传出指定它的 API。除此之外,它与 int 或 long 相比没有优势。至少使用 int 或 long 您知道在 printf 或类似语句中使用什么格式说明符。
如果您需要存储 long 并且您在 64b 系统中工作时使用 NSInteger 但其他用户使用 32b 系统,会发生什么情况?您不会注意到失败,但用户会注意到。
这是倒退。除非您有特殊原因,否则请始终使用 int。对简单整数使用特定于平台的定义只会使您的代码更难阅读。
P
Pontus Granström

为什么要使用 int

Apple 使用 int 是因为对于循环控制变量(仅用于控制循环迭代),int 数据类型很好,无论是数据类型大小还是它可以为循环保存的值。 这里不需要依赖于平台的数据类型。对于循环控制变量,即使是 16 位 int 大部分时间都可以。

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

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


D
Darren

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
斯蒂芬,你的建议是永远不要使用 int、long 或 NSInteger?
不,如果您需要已知固定大小的整数类型,我的建议是永远不要使用它们。 <stdint.h> 类型就是为此目的而存在的。
斯蒂芬,我的回答是回答“何时使用 NSInteger 与 int”这个问题,而不是“什么是 32 位整数的跨平台类型名”。如果有人试图在 NSInteger 和 int 之间做出决定,他们可能也知道他们在他们支持的平台上有多大。
另请注意,LP64 不保证 long long 是 64 位。 LP64 平台可以选择让 long long 为 128 位整数。
E
Evan Mulawski

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

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

简单地说,NSInteger typedef 为您做了一个步骤:如果架构是 32 位,它使用 int,如果是 64 位,它使用 long。使用 NSInteger,您无需担心程序运行的架构。


您确实需要担心,因为 NSInteger 的正确格式说明符取决于架构。
根据 Apple 手册,最简单的方法是将 value 转换为最大的数字类型 long long。所以所有数字类型都将使用相同的类型说明符。
现在最简单的格式化方法就是将它们装箱 - NSLog("%@", @(1123));
您也可以投射它:NSLog("%li", (long)theNSInteger);
选角让我难过
A
Ash

如果您需要将它们与常量值(例如 NSNotFound 或 NSIntegerMax)进行比较,则应该使用 NSIntegers,因为这些值在 32 位和 64 位系统上会有所不同,因此索引值、计数等:使用 NSInteger 或 NSUInteger。

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

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

总体而言,如果您不希望一次将数十万个它们放在内存中,那么使用 NSInteger 比不断担心两者之间的差异更容易。


M
MaddTheSane

在 iOS 上,目前使用 int 还是 NSInteger 并不重要。如果/当 iOS 迁移到 64 位时,它会更重要。

简单地说,NSInteger 是 32 位代码中的 int(因此是 32 位长),而 long 是 64 位代码(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 位代码。

更新 2: 此外,使用 NSInteger 有助于 Swift 代码互操作性。


L
Leon Lucardie

截至目前(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 位值。但是,如果我们在 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 怎么办?它在 64 位环境中都能正常工作吗?我认为它也应该如此,因为我还没有看到这样的 for 循环: for (int i=0;i<10;i++) 做任何错误的行为,无论它运行在什么环境中。
@Cchanchal Raj只要没有转换或转换为其他类型或使用/覆盖涉及该变量的第三方类和方法,使用 int 而不是 NSInteger 就可以了。
g
garg

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


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅