19

为什么 NSIndexPath 的 row 属性是有符号整数?

它会不会出现“有效”的负值?

在此处输入图像描述

编辑

直到今天我设置 LLVM 来检查符号比较时,我才想到这一点。这使得编译器在有indexPath.row <= [someArray count]或类似的时候发出警告。

4

3 回答 3

13

如果使用负数会发生什么?

使用负值是不明智的,如果你这样做,你会得到疯狂的结果

NSIndexPath* path = [NSIndexPath indexPathForRow:-2 inSection:0];

上面的结果是 0 的部分和 4294967294 的行(这NSUInteger对我来说看起来像是下溢!)请注意,这只会发生在 UIKit Additions 类别中,而不是 NSIndexPath 本身。看看背后的概念NSIndexPath,持有负值真的没有意义。所以为什么?

(可能)为什么会这样

OS X的核心对象NSIndexPath使用NSUIntegers 作为其索引,但 UIKit Addition 使用NSInteger. 该类别仅建立在核心对象之上,但使用NSIntegeroverNSUInteger并没有提供任何额外的功能。

为什么它会这样工作,我不知道。我的猜测(我规定猜测)是第一次启动 iOS 时的一个幼稚的 API 失误。在UITableViewiOS 2 中发布时,它使用NSIntegers 表示各种事物(例如numberOfSections)。想一想:这在概念上没有意义,你不能有负数的部分。现在即使在 iOS 6 中,它仍然使用NSInteger, 所以不会破坏以前的应用程序与表格视图的兼容性。

除此之外UITableView,我们还添加了NSIndexPath,它们与表视图一起用于访问它的行等。因为它们必须一起工作,所以它们需要兼容的类型(在这种情况下NSInteger)。

将类型更改为NSUInteger全面会破坏很多东西,并且为了安全的 API 设计,所有内容都需要重命名,以便 NSInteger 和 NSUInteger 对应物可以安全地并肩工作。Apple 可能不想要这种麻烦(开发人员也不想要!),因此他们将其保留为NSInteger.

于 2012-11-27T14:15:14.657 回答
2

一个可能的原因是无符号类型很容易下溢。例如,我的NSUInteger代码中有一个笔画宽度变量。我需要围绕用这个笔划绘制的点创建一个“信封”,因此代码如下:

NSUInteger width = 3;
CGRect envelope = CGRectInset(CGRectZero, -width, -width);
NSLog(@"%@", NSStringFromCGRect(envelope));

使用无符号类型此输出{{inf, inf}, {0, 0}},使用有符号整数您得到{{-3, -3}, {6, 6}}。原因是变量之前的一元减号width会产生下溢。这对某些人来说可能很明显,但会让很多程序员感到惊讶:

NSUInteger a = -1;
NSUInteger b =  1;
NSLog(@"a: %u, b: %u", a, -b); // a: 4294967295, b: 4294967295

因此,即使在使用负值没有意义(笔画宽度不能为负)的情况下,在负上下文中使用该值也是有意义的,这会导致下溢。切换到有符号类型会减少意外,同时仍保持范围相当高。听起来是个不错的妥协。

于 2012-11-27T14:50:53.920 回答
0

我认为 UIKit Additions 是故意NSIndexPath使用类型的。NSInteger如果由于某种原因将负行传递parameter给任何方法(虽然我目前没有看到...),则NSIntegerMax + parameter不会发生自动转换为值,并且任何可能的对象都不会寻找不存在的大得离谱的参数。不过,还有其他方法可以防止这种情况发生,所以这可能只是口味问题。

例如,我不会NSUInteger在类中将其作为参数NSIndexPath,而是NSInteger会检查一个符号NSIndexPath,如果任何参数为负数,则根本不会创建。

于 2014-03-14T10:30:28.017 回答