【问题标题】:When to use NSInteger vs. int何时使用 NSInteger 与 int
【发布时间】:2011-05-25 14:46:30
【问题描述】:

在为 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

【问题讨论】:

    标签: ios objective-c types nsinteger


    【解决方案1】:

    当您不知道您的代码可能在哪种处理器架构上运行时,您通常希望使用NSInteger,因此您可能出于某种原因想要最大可能的整数类型,这在 32 位系统上只是一个 @ 987654323@,而在 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 以及从指定它的API 传递值。除此之外,它与 int 或 long 相比没有优势。至少使用 int 或 long 您知道在 printf 或类似语句中使用什么格式说明符。
    • 如果您需要存储 long 并且您在 64b 系统中工作时使用 NSInteger 但其他用户使用 32b 系统会发生什么?您不会注意到失败,但用户会注意到。
    • 这是倒退的。除非您有特殊原因,否则请始终使用 int。对简单整数使用特定于平台的定义只会使您的代码更难阅读。
    【解决方案2】:

    为什么要使用int

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

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

    他们 [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,你的建议是永远不要使用 int、long 或 NSInteger?
      • 不,如果您需要已知固定大小的整数类型,我的建议是永远不要使用它们。 &lt;stdint.h&gt; 类型就是为此目的而存在的。
      • Stephen,我的回答是针对“何时使用 NSInteger vs int”这个问题,而不是“什么是 32 位整数的跨平台类型名”。如果有人试图在 NSInteger 和 int 之间做出选择,他们可能会知道他们在他们支持的平台上有多大。
      • 还要注意LP64 不保证long long 是64 位。 LP64 平台可以选择将 long long 设为 128 位整数。
      【解决方案4】:

      如果你深入研究 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);
      • 选角让我难过
      【解决方案5】:

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

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

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

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

      【讨论】:

        【解决方案6】:

        在 iOS 上,目前使用 intNSInteger 无关紧要。如果/何时 iOS 迁移到 64 位,这将更重要。

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

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

        更新:随着 iPhone 5s、iPad Air、配备 Retina 的 iPad Mini 和 iOS 7 的推出,您现在可以在 iOS 上构建 64 位代码。

        更新 2:另外,使用 NSIntegers 有助于 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 位值。 但是,如果我们在 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
          • @Cchanchal Raj 只要没有强制转换或转换为其他类型或使用/覆盖涉及该变量的第三方类和方法,使用 int 代替 NSInteger 就可以了。跨度>
          【解决方案8】:

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

          【讨论】:

            猜你喜欢
            • 2010-12-28
            • 1970-01-01
            • 2023-03-30
            • 2014-07-13
            • 2010-12-17
            • 1970-01-01
            • 2011-06-15
            • 1970-01-01
            相关资源
            最近更新 更多