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.
Related
What do parentheses do when evaluating some meaning?
I have faced this in code, when something is checked and they use
if ( (some condition that returns 1) )
{
code
}
So my question is, does this evaluate to true? I would think that it is always false since (1) does not return anything?
Edit: clarification, question is why double parenthesis in if? I know that 1 is true.
The additional parentheses are used when an assignment is used for its truth value. They allow the compiler to distinguish between
if ((var = expr))
which signals intentional combination of assignment and truth value test, and
if (var = expr)
as an unintentional misspelling of if (var == expr).
The convention, carried over from C and C++, is for the compilers to warn on if (var = expr) as a possible misspelling of if (var == expr). They don't warn on if ((var = expr)), because the extra set of parentheses signals to the compiler that the assignment was intended. As rob mayoff explains, clang has a special case not to warn for certain assignments to self, but for many coders the habit remained.
As others said, the generated code is exactly the same with and without the extra parens.
If you write,
if (self = [super init]) { // Warning
// ...
}
The compiler will give you a warning, because it thinks you might have mistyped = as ==. If you add a second set of parentheses, the warning goes away.
if ((self = [super init])) { // No warning
// ...
}
So the extra parentheses are there to make typos less likely. The parentheses do not change the value of the expression.
In general 0 equates to false, NOT 0 to true.
This link explains bool in objective-c: http://www.mindsizzlers.com/2010/04/objective-c-and-the-properties-of-bool/
true and false value of bool and int
boolean value of false is equivalent to the int value of 0.
boolean value of true is equivalent to the int value of non-zero (e.g. 1, 10, 3000, etc)
For example, consider an example of C code below:
bool bValue;
int nValue;
bValue = true;
nValue = 1;
if (bValue == nValue) {
printf("bValue and nValue are the same!\n");
}
// output: bValue and nValue are the same!
Wrapped with multiple parenthesis:
The following two snippets returns exactly the same results.
if ((((((((((((((((((((1)))))))))))))))))))) {
printf("Hello World!\n");
}
returns the same result as:
if (1) {
printf("Hello World!\n");
}
Expression in if statement
Within your given if statement, you must have an expression that resolves to either true or false value. Please refer to this page for example of expression.
-(void)InitWithPwd:(char *)pPwd
{
char szResult[17];
//generate md5 checksum
CC_MD5(pPwd, strlen(pPwd),&szResult[0]);
szResult[16] = 0;
m_csPasswordHash[0]=0;
for(int i = 0;i < 16;i++)
{
char sz[3] = {'\0'};
//crash in blow row. The first pass is ok. The third pass crash.
//I can't understand.
sprintf(&sz[0],"%2.2x",szResult[i]);
strcat(m_csPasswordHash,sz);
}
m_csPasswordHash[32] = 0;
printf("pass:%s\n",m_csPasswordHash);
m_ucPacketType = 1;
}
I want to get the md5 of the password. But above code crash again and again. I can't understand why.
Your buffer (sz) is too small, causing sprintf() to generate a buffer overflow which leads to undefined behavior, in your case a crash.
Note that szResult[1] might be a negative value when viewed as an int (which happens when passing a char-type value to sprintf()), which can cause sprintf() to disregard your field width and precision directives in order to format the full value.
Here is an example showing this problem. The example code is written in C, but that shouldn't matter for this case.
This solves the problem by making sure the incoming data is considered unsigned:
sprintf(sz, "%02x", (unsigned char) szResult[i]);
Not to get confused with the NSString sizeWithFont method that returns a CGSize, what I'm looking for is a method that returns an NSString constrained to a certain CGSize. The reason I want to do this is so that when drawing text with Core Text, I can get append an ellipses (...) to the end of the string. I know NSString's drawInRect method does this for me, but I'm using Core Text, and kCTLineBreakByTruncatingTail truncates the end of each line rather than the end of the string.
There's this method that I found that truncates a string to a certain width, and it's not that hard to change it to make it work for a CGSize, but the algorithm is unbelievably slow for long strings, and is practically unusable. (It took over 10 seconds to truncate a long string). There has to be a more "computer science"/mathematical algorithm way to do this faster. Anyone daring enough to try to come up with a faster implementation?
Edit: I've managed to make this in to a binary algorithm:
-(NSString*)getStringByTruncatingToSize:(CGSize)size string:(NSString*)string withFont:(UIFont*)font
{
int min = 0, max = string.length, mid;
while (min < max) {
mid = (min+max)/2;
NSString *currentString = [string substringWithRange:NSMakeRange(min, mid - min)];
CGSize currentSize = [currentString sizeWithFont:font constrainedToSize:CGSizeMake(size.width, MAXFLOAT)];
if (currentSize.height < size.height){
min = mid + 1;
} else if (currentSize.height > size.height) {
max = mid - 1;
} else {
break;
}
}
NSMutableString *finalString = [[string substringWithRange:NSMakeRange(0, min)] mutableCopy];
if(finalString.length < self.length)
[finalString replaceCharactersInRange:NSMakeRange(finalString.length - 3, 3) withString:#"..."];
return finalString;
}
The problem is that this sometimes cuts the string too short when it has room to spare. I think this is where that last condition comes in to play. How do I make sure it doesn't cut off too much?
Good news! There is a "computer science/mathematical way" to do this faster.
The example you link to does a linear search: it just chops one character at a time from the end of the string until it's short enough. So, the amount of time it takes will scale linearly with the length of the string, and with long strings it will be really slow, as you've discovered.
However, you can easily apply a binary search technique to the string. Instead of starting at the end and dropping off one character at a time, you start in the middle:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
^
You compute the width of "THIS IS THE STRING THAT". If it is too wide, you move your test point to the midpoint of the space on the left. Like this:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
^ |
On the other hand, if it isn't wide enough, you move the test point to the midpoint of the other half:
THIS IS THE STRING THAT YOU WANT TO TRUNCATE
| ^
You repeat this until you find the point that is just under your width limit. Because you're dividing your search area in half each time, you'll never need to compute the width more than log2 N times (where N is the length of the string) which doesn't grow very fast, even for very long strings.
To put it another way, if you double the length of your input string, that's only one additional width computation.
Starting with Wikipedia's binary search sample, here's an example. Note that since we're not looking for an exact match (you want largest that will fit) the logic is slightly different.
int binary_search(NSString *A, float max_width, int imin, int imax)
{
// continue searching while [imin,imax] is not empty
while (imax >= imin)
{
/* calculate the midpoint for roughly equal partition */
int imid = (imin + imax) / 2;
// determine which subarray to search
float width = ComputeWidthOfString([A substringToIndex:imid]);
if (width < max_width)
// change min index to search upper subarray
imin = imid + 1;
else if (width > max_width )
// change max index to search lower subarray
imax = imid - 1;
else
// exact match found at index imid
return imid;
}
// Normally, this is the "not found" case, but we're just looking for
// the best fit, so we return something here.
return imin;
}
You need to do some math or testing to figure out what's the right index at the bottom, but it's definitely imin or imax, plus or minus one.
I need to check a variable vi_theIndex for its value. At the given moment it has a value of 65.
I want to check if vi_theIndex is bigger or equal to zero AND smaller than 32.
Right now I do it like this:
long long vi_theIndex = 65;
if ((vi_theIndex >= 0) && (vi_theIndex < 32) )
{
//Case true
}
else
{
//Case false
}
I realized that the results are wrong for 65. The second case should come up but the first case becomes true. Why is this?
I tried this:
long long vi_theIndex = 65;
bool limitFlag1, limitFlag2;
limitFlag1 = (vi_theIndex <= 0);
limitFlag2 = (vi_theIndex = 65);
limitFlag2 becomes true and limitFlag1 becomes undefined, the debugger doesn´t even stop there on my breakpoint. It looks like C doesn´t understand the '<', '<=' or '>' signs. This also happens when I use the '<' or '>' sign alone like here:
limitFlag1 = (vi_theIndex < 0);
limitFlag1 is not defined.
Can somebody please shed some light on this?
You must not be showing your real code for your first example - as you say, "case false" should be executed.
Your second example has a problem - you have vi_theIndex = 65, rather than vi_theIndex == 65, which you probably meant. The statement as you have it is always true. limitFlag1 will be 0 - I'm not sure what you mean by it "becomes undefined" - are you not showing your real code here, too?
I want to make a selection before apply one of two animations,
what I thought is: make a Point one, if my myImageView is at the Point one, then apply animationNo1, else apply animationNo2, but I got this:"used struct type value where scalar is required", at line if (myImageView.layer.position = one)
What I do? how can I fix this?
Does anyone know exactly what makes the problem happen?
CGPoint one = CGPointMake(myImageView.layer.position.x, 100);
if (myImageView.layer.position = one)
{
animationNo1
}
else
{
animationNo2
}
First of all, your if-statement will not do what you think. If you want to compare something you have to use == (ie 2 =)
and you can't compare CGPoints like this.
use
if (CGPointEqualToPoint(one, self.view.layer.position))
if (myImageView.layer.position = one) { animationNo1 }
should be
if (CGPointIsEqualToPoint(myImageView.layer.position, one)) { animationNo1 }
You used a single = meaning assignment, rather than a == for comparison. But the == wouldn't do what you wanted here anyway.
You are passing a struct (int this case position) instead of a scalar. To do what you want you need to use CGPointIsEqualToPoint:
if (CGPointEqualToPoint(one, self.view.layer.position))
Full code with corrections:
CGPoint one = CGPointMake(myImageView.layer.position.x, 100);
if (CGPointEqualToPoint(one, self.view.layer.position))
{
animationNo1
}
else
{
animationNo2
}
Also, as others have pointed out: Be careful about = vs ==. They are different. In this case you don't use == for comparison fortunately, but if you use = for other stuff it will make it true instead of checking to see if it is true.