Here's a couple lines of code... currentPage is an NSInteger, imageViewHolder is an NSMutableArray.
NSLog(#"currentPage: %d, imageViewHolderCount: %d", currentPage, [imageViewHolder count]);
if(currentPage < [imageViewHolder count] - 1)
{
NSLog(#"%d < %d - 1", currentPage, [imageViewHolder count]);
tempView = [imageViewHolder objectAtIndex:currentPage + 1];
NSLog(#"doesn't get here, crashed."); //this doesn't get logged because of crash.
//do other stuff here
}
I'm crashing at the "tempView = ..." line due to index out of bounds. This is the output I'm getting:
currentPage: 0, imageViewHolderCount: 0
0 < 0 - 1
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds for empty array'
*** First throw call stack:
(0x339bd88f 0x324af259 0x339069db 0x48f1b 0x48c1b 0x35603a85 0x35603409 0x35602c57 0x35716b0f 0x3560424d 0x4abfb 0x324ab175 0x43f77 0x45b91 0x479a7 0x36bff 0x285ed 0x35604ecb 0x32935933 0x33991a33 0x33991699 0x3399026f 0x339134a5 0x3391336d 0x32e91439 0x35608e7d 0xfa01 0xf9c0)
I'm sure I'm missing something obvious... why is my if statement being evaluated as true? I'm fairly certain that 0 is in fact greater than -1 :)
The problem is that count is an unsigned type. When you subtract 1 from an unsigned zero, you end up with a really large positive number1 rather than -1.
Replace the condition with an equivalent expression that uses addition to avoid the problem:
if((currentPage+1) < [imageViewHolder count]) ...
1 The value of -1 in 2-s complement representation used in most modern computers to represent negatives is a binary number composed entirely of ones. When this number gets re-interpreted as an unsigned 32-bit value, it becomes 2^32-1.
Yes, but 0 is much less than MAX_INT. You're working with unsigned integers (I'd have to double-check the standard on whether this is defined as MAX_INT, or undefined behavior that happens to be MAX_INT, but in either case it's never what you mean). I suspect if you look at your compiler output, there's a warning to this effect (never allow any warnings in ObjC code).
See also unsigned long 0 < -1?
this is a long shot ... but try writing your condition like this:
(currentPage < ([imageViewHolder count] - 1))
maybe the problem is that the compiler is grouping it like this
((currentPage < [imageViewHolder count]) - 1)
(0 < 0) returns false (0), then substracts 1, and stays at -1, which is different from 0, so it returns true
Related
I have a method that contains a few conditionals. The first conditional works fine and does not cause any problems. However, the second one causes the app to crash.
- (void)didReceiveGaiaGattResponse:(CSRGaiaGattCommand *)command
{
GaiaCommandType cmdType = [command getCommandId];
NSData *requestPayload = [command getPayload];
uint8_t success = 0;
NSLog(#"cmdType: %li", (long)cmdType);
[requestPayload getBytes:&success range:NSMakeRange(0, sizeof(uint8_t))];
if (cmdType == GaiaCommand_GetCurrentBatteryLevel && requestPayload.length > 1)
{
uint16_t value = 0;
[requestPayload getBytes:&value range:NSMakeRange(1, sizeof(uint16_t))];
NSInteger battery = CFSwapInt16BigToHost(value);
[self sendEventWithName:someDEVICE_BATTERY_CHANGED body:#{#"batteryLevel":[NSNumber numberWithInteger:battery]}];
return;
}
else if (cmdType == GaiaCommand_GET_FBC && requestPayload.length > 1)
{
uint16_t value = 0;
[requestPayload getBytes:&value range:NSMakeRange(1, sizeof(uint16_t))];
NSInteger feedbackCancellationMode = CFSwapInt16BigToHost(value);
[self sendEventWithName:FEEDBACK_CANCELLATION_MODE body:#{#"feedbackCancellationMode": [NSNumber numberWithInt:feedbackCancellationMode]}];
return;
}
//do more stuff
}
The conditional
if (cmdType == GaiaCommand_GetCurrentBatteryLevel &&
requestPayload.length > 1)
works without problems.
However, the conditional
else if (cmdType == GaiaCommand_GET_FBC && requestPayload.length > 1)
causes the following warning in xcode
Implicit conversion loses integer precision: 'NSInteger' (aka 'long')
to 'int'
In addition, I also saw the error message in the debugger
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[_NSInlineData getBytes:range:]: range {1, 2} exceeds
data length 2'
Consider what this is telling you:
Terminating app due to uncaught exception 'NSRangeException', reason:
'-[_NSInlineData getBytes:range:]: range {1, 2} exceeds data length 2'
Your data object is 2 bytes in length. The first byte, at position 0, is (according to your code) the success value. That leaves one more byte at position 1 to handle. But your code is attempt to copy 2 bytes out of it — that's the range {1, 2} in the message; a range starting at position 1 and with a length of 2. You're reading past the end of the data.
You have to check that the data has enough data to satisfy the -getBytes:... call you're attempting to make. You may also need to correct your assumptions about how large the cancellation mode value in the buffer is supposed to be, because it's apparently smaller than you expect. Your code assumes it's a uint16_t (2 bytes) but there's only one byte left in the data.
[NSNumber numberWithInt:feedbackCancellationMode]}]
should be
[NSNumber numberWithInteger: feedbackCancellationMode]}]
For my app (OSX, not IOS) i have a geometric sequence (stored in container array) generated like this:
- (void)initContainerFor:(NSInteger)maxRows
{
self.container = [[NSMutableArray alloc] init];
NSInteger start = [self.firstTextFieldValue integerValue];
NSInteger ratio = [self.secondTextFieldValue integerValue];
// ASCENDING
for (NSInteger i = 1; i < (maxRows +1 ); i++)
{
NSInteger currentValue = start * pow(ratio,i-1);
[self.container addObject:currentValue];
}
}
User can enter the "start" and "ratio" integer. I want to give a feedback if limit (MAX_INT) is exceeded. I wrote this function:
- (BOOL)maxCheck
{
if ([self.container lastObject] > INT_MAX)
return false;
return true;
}
But this seems not to work. If i enter 2 for start and 200 for ratio i have this container content:
Container: (
2,
400,
80000,
16000000,
"-1094967296",
49872896,
1384644608,
2051014656,
"-2113929216",
0
)
Please help to understand what i see in the container (strings??) and how to get a correct check for the maximum value.
As you can see from log of array, you actually exceed INT_MAX limit twice, when next element become negative. So you can just add check to initContainer: method - if element is less then the previous, INT_MAX limit is reached.
TIP: INT_MAX is a signed value.
You can not compare the value after overflow with INT_MAX, as the overflow already happened. Or put differently, by its very definition and semantics, no integer can be bigger than INT_MAX.
What you can test is
[self.container lastObject] > INT_MAX/ratio
to find the sequence element that would cause overflow in the next step.
I am writing some unit tests for a map coordinate function that I am writing. Unfortunately, there's something going on with XCTest that I am unable to nail down that is causing my test to fail:
NSString *testValue = #"121°31'40\"E";
double returnValue = coordinateStringToDecimal(testValue);
static double expectedValue = 121.5277777777778;
XCTAssertEqual(returnValue, expectedValue, #"Expected %f, got %f", expectedValue, returnValue);
I did read this similar question to troubleshoot. However, I am able to validate that the numbers and types are the same. Here is the console output of checking the type of each value:
(lldb) print #encode(__typeof__(returnValue))
(const char [2]) $5 = "d"
(lldb) print #encode(__typeof__(expectedValue))
(const char [2]) $6 = "d"
The Variables View in the debugger is showing them to be the same:
The interesting thing is the console output of comparing them in lldb:
(lldb) print (returnValue == expectedValue)
(bool) $7 = false
The types are the same and the actual numbers are the same. Why else would my assert be failing???
Because you are dealing with floating point numbers, there will always be a certain degree of inaccuracy, even between double values. In these cases, you need to use a different assertion: XCTAssertEqualWithAccuracy. From the docs:
Generates a failure when a1 is not equal to a2 within + or - accuracy. This test is for scalars such as floats and doubles, where small differences could make these items not exactly equal, but works for all scalars.
Change your assert to something like this:
XCTAssertEqualWithAccuracy(returnValue, expectedValue, 0.000000001);
Or in Swift 4:
XCTAssertEqual(returnValue, expectedValue, accuracy: 0.000000001, "expected better from you")
In Nimble:
expect(expectedValue).to(beCloseTo(returnValue, within: 0.000000001))
In Swift 4 accuracy was removed from the function name - now its an overload of XCTAssertEqual:
XCTAssertEqual(returnValue, expectedValue, accuracy: 0.000000001, "expected better from you")
I'm trying to write code that detects if an integer is greater than another integer. Is this possible?
Here is what i've done so far.
if (NumCorrect >> NumWrong) {
btnCool.title = #"Awww";
}
else {
btnCool.title = #"Cool!";
}
All its doing is going to the else
EDIT:
NSString *numCorrect = [NSString stringWithFormat:#"%d",NumCorrect];
NSString *numWrong = [NSString stringWithFormat:#"%d", NumWrong];
lblWrong.text = numWrong;
lblCorrect.text = numCorrect;
if (NumCorrect > NumWrong) {
btnCool.title = #"Awww";
} else {
btnCool.title = #"Cool!";
}
Use single >
if (NumCorrect > NumWrong) {
btnCool.title = #"Awww";
} else {
btnCool.title = #"Cool!";
}
Double >> is a bit shift operation. You shift every bit in the binary representation of your variable NumCorrect NumWrong amount of bytes to the right. In almost all cases this will return in a number other then 0, which will then treated as a false value and thus the else block is executed.
Almost perfect - just take off one of those >'s. >> and << are for "bit-shifting", a weird hold-over from the earliest days of programming. You're not gonna use them much. What you really want is > and <, which is for testing if numbers are greater than each other or less than each other.
In addition, you may remember from math class that ≥ and ≤ (greater-than-or-equal-to and less-than-or-equal-to) are useful operations as well. Because there's no symbols for those on most keyboards, however, C and Xcode use >= and <= instead.
Finally, you may already know this, but to check if two numbers are exactly equal to each other you can use == (because = is used for setting the contents of variables).
Hope that's helpful!
I am trying to compare a CGFloat to an integer value. Based on this value, execute a conditional... pretty standard. However, this will always be true for some reason. I even print out the values and they are clearly less than 800.... I have tried a bunch of different combinations, the most recent is shown below, I thought maybe it was comparing the size of float and the size of the int based purely on its binary values, so I tried this risky little cast operation... Any ideas?
CGPoint textViewPoint = [scroller convertPoint:[textView center] toView:(UIView *)self.view];
NSLog(#"the y coord is %f", textViewPoint.y);
int size = (int)textViewPoint.y;
NSLog(#"the yint %d", size);
//move the main view, so that the keyboard does not hide it.
//if (self.scroller.frame.origin.y >= 0 && textViewPoint.y > 800.0);
if(size > 800);
{
NSLog(#"moving up");
The problem is the ; at the end of the if(size > 800); line, not the int vs. float comparison. Remove it and all should be OK.
This is because this semicolon is interpreted as the body of your if statement, and that's this NO-OP statement that is executed when the condition is true. Then, the rest of your code next to this if empty body is outside of the if body so is executed whatever the condition value. That's exactly as if you had written:
if(size > 800)
{
}
{
NSLog(#"moving up");
}
Compiler Warning Tip
The compiler generally warns you about this mistake. Be sure that you have the "Empty Loop Bodies" warning activated in your project Build Settings (compiler flag -Wempty-body): this way the next time you do this mistake, you will have a warning about it and will know what is wrong and how to fix it.