问题
I am in doubt, why this work correctly:
NSInteger row = indexPath.row;
NSInteger preloadTrigger = self.nodes.count - 20;
if (row >= preloadTrigger) {
[self.loader loadNextposts];
}
And this does not (just skips the if-statement):
if (indexPath.row >= self.nodes.count - 20) {
[self.loader loadNextposts];
}
when the value of self.nodes.count - 20
is negative.
However, when the value of the expression is positive, it works fine always.
A very strange behavior, as I cannot see semantic difference in two expressions.
Update: So, I decided to test it:
(lldb) po self.nodes.count - 20
18446744073709551601
(lldb) po preloadTrigger
-15
回答1:
According to Apple Docs, count property is a NSUInteger
in objective-C.
When you write :
NSInteger preloadTrigger = self.nodes.count - 20;
In fact you are casting count
to a NSInteger
object, and can have a negative value if count
isn't greater than 20.
But when you write :
(indexPath.row >= self.nodes.count - 20)
count
is a NSUInteger
object, and subtract 20 from it will always lead to a positive number (a huge one by the way).
回答2:
Because nodes.count is NSUInteger and row is NSInteger. Unsigned integer - 20 is never a negative value, but results a huge positive value where you expect it to be negative.
回答3:
I'll add some explanation to the other, correct answers.
So, here is how it goes:
self.nodes.count
is of type NSUInteger, which is the same as unsigned long int
in 64 bit systems, or alternatively unsigned int
in 32 bit systems.
The literal 20
is of type int
.
When you form the expression self.nodes.count - 20
, 20
is 'promoted' to the unsigned integer type of the other operand (self.nodes.count
), because it has the wider range of the two.
That is because, when both operands have types of different sizes, the smaller one gets promoted to the larger one to make them equal and calculate the result in those terms (in hardware, arithmetical operations between values of different types aren't really defined - the bit representations differ).
The problem is that, in exchange for being able to represent a wider range of positive values with the same bit length, unsigned integers can not represent negative values. So, when 20
is greater than self.nodes.count
, the result "wraps around" to a large, unsigned integer.
On the other hand indexPath.row
, too, is an unsigned integer (NSUInteger
), so you end up comparing the relatively small row value with the huge result of the subtraction operation; the test:
if (indexPath.row >= self.nodes.count - 20)
...always fails (the left side is smaller).
If you first cast both results to signed integer and then compare those signed integers:
NSInteger row = indexPath.row;
NSInteger preloadTrigger = self.nodes.count - 20;
if (row >= preloadTrigger) {
...then no wrapping/underflow occurs and you get the expected result.
来源:https://stackoverflow.com/questions/35265279/evaluation-nsintegers-inside-if-statement-objective-c