If "a == b" is false when comparing two NSString objects - objective-c

I have a class with an accessible method that passes back an NSString when called.
[MyClass getMyString]
The string variable in that class is actually assigned in the didSelectRowAtIndexPath: part of a table like this:
myString = cell.textLabel.text;
When I retrieve the string by calling that method, I assign it to another string in the class that called it and compare it to a string I have defined
NSString *mySecondString;
mySecondString = #"my value";
if(mySecondString == myString){
i = 9;
}
I have stepped through the code and every time it evaluates the if statement, it skips right past the i=9 and goes to the next else if statement. Why would this be? Why don't they evaluate to be the same value? If you hover your cursor over each of the values during debugging they will show they have the same value, but the code for some reason with not do as I expect it to do and assign 9 to i.
Any thoughts?

You're assuming that the C == operator does string equality. It doesn't. It does pointer equality (when called on pointers). If you want to do a real string equality test you need to use the -isEqual: method (or the specialization -isEqualToString: when you know both objects are strings):
if ([mySecondString isEqualToString:myString]) {
i = 9;
}

You are comparing pointers to strings, rather than the strings themselves. You need to change your code to
if (if([mySecondString isEqualToString:myString]) {
....
}

you can not use '==' to compare two NSString
you should to use [NSString isEqualToString:(NSString*)] to compare two string

You can not compare the two string using "==" this is for int and other values.
you can use below code for the comparing two string
if ([Firststring isEqualToString:Secondstring]) {
NSLog(#"Hello this both string is same ");
}

It's a basic concept of pointer, you are missing. (YES, myString and mySecondString are pointers to the string).
Now, if(mySecondString == myString) will go TRUE only if, both the pointers are pointing to the same location. (Which they won't in most cases)
You should be doing if ([mySecondString isEqualToString:myString]), which will be comparing your both string's content for equality.

Related

Comparison between pointer and int (id to int) - Object wrapping still doesn't work [duplicate]

So my problem is this:
I am receiving a JSON string from across the network. When decoded (using SBJSON libraries), it becomes an NSDictionary that SHOULD contain a number of some sort for the key 'userid'. I say 'should' because when I compare the value to an int, or an NSINTEGER, or NSNumber, it never evaluates correctly.
Here is the comparison in code:
NSDictionary *userDictionary = [userInfo objectAtIndex:indexPath.row];
if ([userDictionary objectForKey:#"userid"] == -1) {
//Do stuff
}
The value inside the dictionary I am testing with is -1. When I print it out to console using NSLog it even shows it is -1. Yet when I compare it to -1 in the 'if' statement, it evaluates to false when it should be true. I've even tried comparing to [NSNumber numberWithInt: -1], and it still evaluates to false.
What am I doing wrong? Thanks in advance for your help!
You are comparing a pointer to an object, not an integer itself. You must first convert the object into an integer:
if ([[userDictionary objectForKey:#"userid"] integerValue] == -1)
{
//Do stuff
}

Why a mutable copy of a NSString is said to be equal to the original immutable one?

Suppose I have a NSString* str1 and NSMutableString* str2, and I make str2 the mutable copy of str1. And I called the following method:
-(void)someMethod {
NSString *str1;
NSMutableString *str2;
str1 = #"OK";
str2 = [str1 mutableCopy];
if ([str2 isEqual:str1]) {
NSLog(#"Same!");
}
else {
NSLog(#"Not exactly!");
}
NSLog(#"%#", [[str1 class] description]);
NSLog(#"%#", [[str2 class] description]);
}
Console output:
2014-01-07 14:03:16.291 LearnFoundation[3739:303] Same!
2014-01-07 14:03:16.293 LearnFoundation[3739:303] __NSCFConstantString
2014-01-07 14:03:16.293 LearnFoundation[3739:303] __NSCFString
So here comes the confusion, according to the documentation of isEqual in NSString, it returns a Boolean value that indicates whether the receiver and a given object are equal. So why the mutable copy is said to be the same as the original immutable one?
Thanks in advance!
There are (at least) three separate concepts that can all be thought of as "equality":
"identity" (am I the same object as that other object?)
"equality" (am I exactly identical to this other object?)
"value equality" (do I have the same value as this other object?)
For ObjC objects you test for equal identities with ==, but equivalent values with isEqual:. There's no one-stop shop method for testing exact equality; it turns out to not be very useful, in general.
In Javascript (for comparison's sake), you test for equal identities with === and equivalent values with ==. There is similarly no direct way to test for exact equality.
For pass-by-value types like int and float, there's no such thing as identity, since you can't pass a particular instance around. However, if you squint a bit, you can think of this as being a similar case of different types with the same value:
int x = 5;
short y = 5;
if (x == y) {
...
}
Though in this case it's not a subtype relationship.
isEqual compares the contents of the two strings, not their types or identities. The contents are equal so it evaluates true.
To compare types, try:
if([str1 isKindOfClass:[str2 class]])
{
NSLog(#"same");
}else{
NSLog(#"different");
}
You should see "different" get logged.
They're equal as strings, but are distinct objects with distinct addresses. Thus, isEqual returns YES but a comparison with == would evaluate to NO.

How to insert "nil" values into an array bound to a tableview?

I'd like to have some hints about one thing:
In an array, bound to a tableview column, I have some numeric (float) values. These values are entered (put into the array) using interface buttons, labelled "0", "1", "2" and so on. There is also a "C" button to cancel an entry.
Later, I have some calculations to do with this array. If no result was entered, the array's object cannot be 0. "No value" is certainly better represented by "nil"… but you are not allowed to insert a nil object into an array (nil means "end of array").
A NSArray contains objects. That is, here, these object must be NSNumbers. So I can initialize my array by filling it with [NSNumber numberWithDouble:…] double what? I cannot put nil here!
A true NSArray does not (can not) contain "holes". But mine has to, if for example, the third item never received a value. How can I:
implement an "undefined" value for my NSNumber?
make the "C" button erase a previously entered result?
There must be a solution. In ApplescriptObjC I used a trick: I did the attribution in the method called by every button, using its title, so:
if sender's title as string is "C" then
set item theRow of gResult to missing value -- the row was the selected line, gResult was a AS list.
else
set item theRow of gResult to sender's title as real
end if
What should I do here?
- choose a special value (say -1) to indicate an undefined value, then use a NSPredicate to filter my array?
- how could I turn the cell to "nothing" as the special value IS something and appear into the cell (even )
I'm sure there is an elegant solution to this problem. But for now I just tear out what little hair I have left…
Thank for help…
You can add an NSNull object to represent a null value.
An NSArray must always contains objects, nil is a flag indicating the end of the array. Thus in order to represent a nil value as an object you should use NSNull as follows:
[NSNull null]
You need a 'distinguished' object in your NSArray. When you see that distinguished object, your code does something different. Such a 'distinguished' object is often called a 'sentinel' and it can be anything. For example:
static NSNumber *theSentinel;
/* initialize theSentinel somewhere with */
theSentinel = [NSNumber numberWithFloat: <anyfloat-doesnt'-matter-which>];
then in your code:
NSNumber *selection = [NSArray objectAtIndex: <user selection>];
if (selection == theSentinel) { /* something */ }
else { /* main */ }
And in your predicates you can use (in words, not code):
predicate = (obj NOT EQUAL theSentinel) AND (rest of your predicate based on float)

Compare the text of two text fields

How do you compare the text in two text fields to see if they are the same, such as in "Password" and "Confirm Password" text fields?
if (passwordField == passwordConfirmField) {
//they are equal to each other
} else {
//they are not equal to each other
}
In Objective-C you should use isEqualToString:, like so:
if ([passwordField.text isEqualToString:passwordConfirmField.text]) {
//they are equal to each other
} else {
//they are *not* equal to each other
}
NSString is a pointer type. When you use == you are actually comparing two memory addresses, not two values. The text properties of your fields are 2 different objects, with different addresses.
So == will always1 return false.
In Swift things are a bit different. The Swift String type conforms to the Equatable protocol. Meaning it provides you with equality by implementing the operator ==. Making the following code safe to use:
let string1: String = "text"
let string2: String = "text"
if string1 == string2 {
print("equal")
}
And what if string2 was declared as an NSString?
let string2: NSString = "text"
The use of == remains safe, thanks to some bridging done between String and NSString in Swift.
1: Funnily, if two NSString object have the same value, the compiler may do some optimization under the hood and re-use the same object. So it is possible that == could return true in some cases. Obviously this not something you want to rely upon.
You can do this by using the isEqualToString: method of NSString like so:
NSString *password = passwordField.text;
NSString *confirmPassword = passwordConfirmField.text;
if([password isEqualToString: confirmPassword]) {
// password correctly repeated
} else {
// nope, passwords don't match
}
Hope this helps!

Reading a text field and comparing to an array object?

I have setup an array full of words as objects. I am trying then trying to compare what the user enters in a uitextfield to an object in the array to see if they match.
I have captured a pointer to the uitextview in one of the delegate methods, however I cannot compare the text field contents to the object in the array. I assume that this is because one is a string and one is an array object ? Do I need to cast one of the variables somehow ?
Thanks
Martin
Assuming you want to test whether the user's input matches any member of your array, you should do something like this:
NSString *input = textField.text;
BOOL wordFound = NO;
for(NSString *candidate in self.possibleWordsArray) {
if( [input isEqual:candidate] ) {
wordFound = YES;
break;
}
}
if(wordFound) {
...
}
else {
...
}
Notes:
We are comparing the input string against each member of the array in turn. This gives an explicit meaning to the idea of matching a string against an array.
When we find a matching string, we set the flag wordFound to YES and then stop searching (using the break statement). If no match is found, the wordFound flag remains at its original value of NO.
Always use isEqual to test equality between strings, never ==; the later will usually work, but then break occasionally. This is because == only tests whether the two pointers point to the same memory location, whereas you might have two copies of an identical string in different memory locations.