How to compare strings? (`==` returns wrong value) - iphone

I've got myself a piece of the iPhone SDK and been trying to make some simple apps. In this one, i want to compare the first character of self.label.string with the last one of ((UITextField *)sender).text. I decided to name them self.texty and self.input, respectively.
I would expect this if statement returning yes to me under certain circumstances, however I can't seem to get that done.
(in my case, my self.label.string was equal to 'hello!', while my self.input ended in an 'h'.)
self.input = [NSString stringWithFormat:#"%#", [((UITextField *)sender).text substringFromIndex:[((UITextField *)sender).text length]-1]];
self.texty = [NSString stringWithFormat:#"%#", [self.label.string substringToIndex:1]];
if (self.input == self.texty) {
return yes;
} else {
return no;
}

String comparison is not done with ==, but with one of the comparison methods of NSString.
For example:
if ([self.input compare:self.texty] == NSOrderedSame) {

if ([self.input isEqualToString:texty]) {
return yes;
} else {
return no;
}
EDIT:
Or a better version as the commenters noted:
return [self.input isEqualToString:texty];

If you're curious why the == operator doesn't work as expected, it's because you're actually comparing two scalar types (pointers to NSString objects) not the contents of the NSString objects themselves. As a result, it will return false unless the two compared NSStrings are actually the same instance in memory, regardless of the contents.

Related

NSString or NSCFString in xcode?

I m taking a NSMutabledictionary object in NSString like this :
NSString *state=[d valueForKey:#"State"];
Now sometimes state may be null and sometimes filled with text.So Im comparing it.While comparing state becomes NSString sometimes and NSCFString othertimes..So unable to get the desired result..
if([state isEqualToString#""])
{
//do something
}
else
{
//do something
}
So while comparing it is returning nil sometimes.So immediately jumping into the else block.
I need a standard way to compare if the state is empty whether it is a NSString or NSCFString ...
How can I do it?
If you're unable to get the result you want, I can assure you it's not because you get a NSCFString instead of a NSString.
In Objective-C, the framework is filled with cluster classes; that is, you see a class in the documentation, and in fact, it's just an interface. The framework has instead its own implementations of these classes. For instance, as you noted, the NSString class is often represented by the NSCFString class instead; and there are a few others, like NSConstantString and NSPathStore2, that are in fact subclasses of NSString, and that will behave just like you expect.
Your issue, from what I see...
Now sometimes state may be null and sometimes filled with text.
... is that in Objective-C, it's legal to call a method on nil. (Nil is the Objective-C concept of null in other languages like C# and Java.) However, when you do, the return value is always zeroed; so if you string is nil, any equality comparison to it made with a method will return NO, even if you compare against nil. And even then, please note that an empty string is not the same thing as nil, since nil can be seen as the absence of anything. An empty string doesn't have characters, but hey, at least it's there. nil means there's nothing.
So instead of using a method to compare state to an empty string, you probably need to check that state is not nil, using simple pointer equality.
if(state == nil)
{
//do something
}
else
{
//do something
}
You can do this
if([state isEqualToString:#""])
{
//do something
}
else
{
//do something
}
You must have to type cast it to get the correct answer.
NSString *state = (NSString *) [d valueForKey:#"State"];
if(state != nil)
{
if(state.length > 0)
{
//string contains characters
}
}

Testing object equality, i.e. the same physical address?

I am checking if an object I am getting back from the NSURLConnectionDataDelegate is the same object that I originally created. What I have been doing is:
// TESTING TO SEE IF THE RETURNED OBJECT IS THE SAME ONE I CREATED
if(connection == [self connectionPartial]) {
But was just curious is this is the same as doing:
if([connection isEqual:[self connectionPartial]]) {
It's not the same.
if(connection == [self connectionPartial]) {
This compares the address of the objects, eg. if the pointers point to the same instance.
if([connection isEqual:[self connectionPartial]]) {
This compares the contents of the objects. For instance for two separate NSString instances, this will return YES as long as the string content is the same:
NSString *s1 = #"Something";
NSString *s2 = #"Something";
BOOL sameInstances = (s1 == s2); // will be false, since they are separate objects.
BOOL sameContent = [s1 isEqual:s2]; // will be true, because they both are "Something"
The first snippet compares the values of the pointers themselves, just as if they were any primitive type like an int. If the addresses are the same, the expression will evaluate true.
The second sends the message isEqual: to one of the connection instances. Any class can override isEqual: to define "equality" with another instance. It's entirely possible for a class's implementation of isEqual: to be:
- (BOOL)isEqual: (id)obj
{
return arc4random_uniform(2) ? YES: NO;
}
So, no, for almost all classes they are not equivalent. (NSObject, which has the "default" implementation of isEqual:, uses the objects' hashes, which, again by default, are their addresses.)
It sounds like using the equality operator, ==, is correct in your case.

Making the app recognize "the right answer"

I am new in the game, so probably an easy issue. What I am trying to do is to make an app with a question asked, and a textFiled in which to answer. Then, i want the app to recognize when the answer is right (in this case the number 25) and when it is wrong (not 25). Everything is working fine, and I get the "wrong" message, but I cant make it recognize the right answer.
- (IBAction)btnSubmitAction:(id)sender {
if (textFieldAnswer.text == #"25") {
lblAnswer.text = #"Yes, your right!";
btnNext.hidden = 0;
} else {
lblAnswer.text = #"No, try again.";
}
}
Thanks a lot!
Well, this is how you're supposed to compare strings:
- (IBAction)btnSubmitAction:(id)sender {
if ([textFieldAnswer.text isEqualToString:#"25"]) {
lblAnswer.text = #"Yes, you're right!";
btnNext.hidden = NO;
} else {
lblAnswer.text = #"No, try again.";
}
}
Comparing objects in Objective-C is done by ==. This means that you compare pointers, which is not the same as comparing strings, because they are pointers. If you would like to compare strings for equality you should call the BOOL instance method isEqualToString of NSString class.
[string1 isEqualToString:#"someString"]

What's most performant way in iOS to check if a string is one of a list of strings?

I want to see if stringA is equal to any of a list of strings -- string1, string2, string3. What's the most performant way to do the comparison?
Since my comparison list is rather small, I'm currently trying this:
- (BOOL) isStringInList:(NSString *)testString{
if ([testString caseInsensitiveCompare:#"string1"] == NSOrderedSame)
return YES;
else if ([testString caseInsensitiveCompare:#"string2"] == NSOrderedSame)
return YES;
else if ([testString caseInsensitiveCompare:#"string3"] == NSOrderedSame)
return YES;
return NO;
}
This obviously does not scale well if I have many strings to compare against. I'd prefer more of a method signature like this -(BOOL) isString:(NSString *)testString inList:(NSString *)listString where listString is a space-separated string of keywords.
Any thoughts on how to improve performance would be appreciated.
The most performant way is to construct an NSSet of the strings you want to compare against and use -member: to test. Once the set is constructed, this will be a constant-time test. If you have a space-separated list to start with, you can use
NSSet *set = [NSSet setWithArray:[listOfWords componentsSeparatedByString:#" "]]
Constructing the set will be linear on the size of the input string. If your set is the same every time, you can construct it once and hold on to the result. To do the actual test you can use
[set member:myWord]
If the result is nil, your word isn't in the set. If it's non-nil, it is. Note, this is a case-sensitive search. If you need case-insensitivity, then you should either lowercase or uppercase both the list of words and the input word before performing your test.
- (BOOL)isString:(NSString*)testString inList:(NSString*)listString
{
BOOL result = NO;
if (testString != nil)
{
NSRange range = [listString rangeOfString:testString];
result = (range.location != NSNotFound);
}
return result;
}
- (BOOL)isString:(NSString *)testString inList:(NSString *)spaceSeparatedStrings
{
NSArray *list = [spaceSeparatedStrings componentsSeparatedByString:#" "];
return [list containsObject:testString];
}
Note: the above will be case-sensative, unlike your example. For case-insensative, you will probably have to iterate over some portion of the NSArray.
According to this, containsObject is more efficient than I would have guessed. Good news.
A binary search tree might be better, but obviously, that would take some work.

curious what is wrong with this if statement?

Could someone explain what is wrong with this "if statement"? I get:
"lvalue required as left operand of assignment".
This does not work:
if ([[prepDataArray objectAtIndex:iNDEX] boolValue] = YES) {
NSLog(#"HARD");
}
While this works:
diffQ = [[prepDataArray objectAtIndex:iNDEX] boolValue];
if (diffQ = YES) {
NSLog(#"HARD");
}
I do realize where the problem are and that the 'lvalue' indicate that i need to have something different on the left side but i do not grasp why and how to do what i want inside the 'if' statement as tried in the first example.
Would appreciate if someone nice could give me a hint :-)
if ([[prepDataArray objectAtIndex:iNDEX] boolValue] == YES) {
NSLog(#"HARD");
}
it's == not =
The first one doesn't work because you try to assign a BOOL (YES) to a message. The second one works because you try to assign a BOOL to diffQ. This is correct, but not the result you expect (comparing diffQ to YES)
Common programming error ;) I've done this a millions times
I completely agree with what #thomas said above, but let me add.
Don't compare a bool to YES. It's not that the if construct requires
if( some comparison statement ) {
....
}
That's not the case. The if construct has the following form:
if( a boolean value) {
...
}
It just happens that a comparison statement yields a boolean, so you put that in the if statement.
In your case, boolValue already gives you a bool. You don't need to compare that against YES or NO. That's like doing YES==YES or YES==NO and it's completely redundant.
Just do
if ([[prepDataArray objectAtIndex:iNDEX] boolValue]) {
NSLog(#"HARD");
}