Basic objective-c question re comparisons in if statement - objective-c

I feel embarrassed asking this, but it seems like something I need to understand:
Why does this evaluate to true? (if I cast it to int it properly evaluates to false)
NSString *var1 = #"ABC";
NSString *var2 = #"ABCD";
if (([var1 length] - [var2 length]) > 2) NSLog(#"-1 > 2");

length is unsigned.
See docs:
length
Returns the number of Unicode characters in the receiver.
- (NSUInteger)length
Return Value
The number of Unicode characters in the receiver.

Related

What happened to Objective-C's "stringWithFormat:" method?

When I define
NSString *testString = [NSString stringWithFormat:#"%4d", 543210];
then testString is #"543210", instead of #"3210"
This used to work in Xcode v4.3.1 but now I upgraded to v4.6 and it stopped working.
Any ideas?
then testString is #"543210", instead of #"3210"
That's the correct behavior anyway. The %Nd format specifier doesn't limit the field with of the number being formatted - it only pads it with space if the field with is greater than the number of characters required to represent the number. If you got 3210 previously, that's erroneous.
If you want to format a number so at most its last four digits are printed, then you can do something like this:
NSString *numStr = [NSString stringWithFormat:#"%d", 543210]; // or whatever
if (numStr.length > 4) {
numStr = [numStr substringFromIndex:numStr.length - 4];
}
Another alternative, has the benefit of being short:
NSString *testString = [NSString stringWithFormat:#"%4d", 543210 % 10000];
The modulus operator % returns the remainder, so if you % 10000 you get the 4 least significant digits.

Objective-C NSString for loop with characterAtIndex

I'm trying to loop through a NSString, character by character, but I'm getting a EXC_BAD_ACCESS error. Do you have an idea how to do this right? I've been googling for hours now but can't figure it out.
Here is my code (.m):
self.textLength = [self.text length];
for (int position=0; position < self.textLength; position++) {
NSLog(#"%#", [self.text characterAtIndex:position]);
if ([[self.text characterAtIndex:position] isEqualToString:#"."]){
NSLog(#"it's a .");
}
}
Thanks a lot!
Characters are not object. characterAtIndex returns unichar, which is actually an integer type unsigned short. You need to use %C instead of %# in NSLog. Also character is not a NSString, so you can't send it isEqualToString. You need to use ch == '.' to compare ch against '.'.
unichar ch = [self.text characterAtIndex:position];
NSLog(#"%C", ch);
if (ch == '.') {} // single quotes around dot, not double quotes
Note that, 'a' is character, "a" is C string and #"a" is NSString. They all are different types.
When you are using %# with unichar ch in NSLog, it is trying to print an object from memory location ch which is invalid. Thus you are getting a EXC_BAD_ACCESS.
characterAtIndex: returns a unichar, so you should use NSLog(#"%C", ...) instead of #"%#".
You also cannot use isEqualToString for a unichar, just use == '.' is fine.
If you want to find the position of all '.'s, you can use rangeOfString. Refer to:
String Programming Guide: Searching, Comparing, and Sorting Strings
Position of a character in a NSString or NSMutableString
characterAtIndex: returns a unichar, which is declared as typedef unsigned short unichar; The format specifier you are using in your calls to NSLog are incorrect, you could just do NSLog(#"%u",[self.text characterAtIndex:position]); or NSLog(#"%C",[self.text characterAtIndex:position]); if you want the actual character to print out.
Also, as a result of unichar being defined the way that it is, it's not a string, so you cannot compare it to other strings. Try something like:
unichar textCharacter = '.';
if ([self.text characterAtPosition:position] == testCharacter) {
// do stuff
}
If you want to find the location of a character in a string you can use this:
NSUInteger position = [text rangeOfString:#"."].location;
if the character or text is not found you will get a NSNotFound:
if(position==NSNotFound)
NSLog(#"text not found!");

How to get an ascii value of a NSString*, pointing to a character?

When presented with an #"a", i'd like to be able to get it's ascii value of 97.
I thought this does it
NSString *c = [[NSString alloc] initWithString:#"a"];
NSLog(#"%d", [c intValue]); // Prints 0, expected 97
But ... you guessed it (or knew it :)) .. it does not.
How can i get an ascii value of a NSString*, pointing to a single character?
NSString *str = #"a";
unichar chr = [str characterAtIndex:0];
NSLog(#"ascii value %d", chr);
And why your method does not work is because you are operating on a STRING remember? Not a single character. Its still a NSString.
NSLog(#"%d",[c characterAtIndex:0]);
NSString class reference: The integer value of the receiver’s text, assuming a decimal representation and skipping whitespace at the beginning of the string. Returns INT_MAX or INT_MIN on overflow. Returns 0 if the receiver doesn’t begin with a valid decimal text representation of a number.
So it returned 0 because you called intValue on invalid decimal text representation of a number.

Converting NSNumber to NSString is not realy a string

I have got a problem with converting an NSNumber value to an NSString
MyPowerOnOrNot is an NSNumber witch can only return a 1 or 0
and myString is an NSString..
myString = [NSString stringWithFormat:#"%d", [myPowerOnOrNot stringValue]];
NSLog(#"%#",myString);
if(myString == #"1") {
[tablearrayPOWERSTATUS addObject:[NSString stringWithFormat:#"%#",#"ON"]];
}
else if(myString == #"0") {
[tablearrayPOWERSTATUS addObject:[NSString stringWithFormat:#"%#",#"OFF"]];
}
What is wrong with this?
The NSLog shows 0 or 1 in the console as a string but I can't check it if it is 1 or 0 in an if statement?
If doesn't jump into the statements when it actually should.. I really don't understand why this doesn't works..
Any help would be very nice!
A couple of problems
myString = [NSString stringWithFormat:#"%d", [myPowerOnOrNot stringValue]];
-stringValue sent to an NSNumber gives you a reference to a string. The format specifier %d is for the C int type. What would happen in this case is that myString would contain the address of the NSString returned by [myPowerOnOrNot stringValue]. Or, on 64 bit, it would return half of that address. You could actually use [myPowerOnOrNot stringValue] directly and avoid the relatively expensive -stringWithFormat:
if(myString == #"1")
myString and #"1" are not necessarily the same object. Your condition only checks that the references are identical. In general with Objective-C you should use -isEqual: for equality of objects, but as we know these are strings, you can use -isEqualToString:
if ([[myPowerOnOrNot stringValue] isEqualToString: #"1"])
Or even better, do a numeric comparison of your NSNumber converted to an int.
if ([myPowerOnOrNot intValue] == 1)
Finally if myPowerOnOrNot is not supposed to have any value other than 0 or 1, consider having a catchall else that asserts or throws an exception just in case myPowerOnOrNot accidentally gets set wrong by a bug.
"myString " is a reference to a string, not the value of the string itself.
The == operator will compare the reference to your string literal and so never return true.
Instead use
if( [myString isEqualToString:#"1"] )
This will compare the value of myString to "1"
In Objective C; you can't compare strings for equality using the == operator.
What you want to do here is as follows:
[tablearrayPOWERSTATUS addObject:([myPowerOnOrNot integerValue]?#"ON":#"OFF"])];
Compact, fast, delicious.

Objective C unicode character comparisons

How are unicode comparisons coded? I need to test exactly as below, checking for specific letters in a string. The code below chokes: warning: comparison between pointer and integer
for (charIndex = 0; charIndex < [myString length]; charIndex++)
{
unichar testChar = [myString characterAtIndex:charIndex];
if (testChar == "A")
// do something
if (testChar == "B")
// do something
if (testChar == "C")
// do something
}
For char literals, use single quotes:
if (testChar == 'A') NSLog(#"It's an A");
Or represent the character using the code point number:
if (testChar == 0x1e01) NSLog(#"It's an A with a ring below");
The compiler sees double-quotes as a string, so builds "A" as equivalent to a const char * (which gives you there error message about the pointer).
What are you really trying to do? Doing direct character comparisons is unusual. Typically -compare: or -isEqual: would be used to compare two strings. Or NSScanner would be used to analyze the components of a string.