If statement expecting ] - objective-c

if (menuPlayed == TRUE && [sender tag == 0]) {
NSLog(#"You're pressing the right button at the right time");
}
Any idea why this is throwing up a "Expected "]
"" error? I have absolutely no idea what's wrong with those comparisons :(

Change:
if (menuPlayed == TRUE && [sender tag == 0])
to:
if (menuPlayed == TRUE && [sender tag] == 0)
Also note that you should never write expressions such as menuPlayed == TRUE - always write this as just menuPlayed, i.e. in this particular case:
if (menuPlayed && [sender tag] == 0)
And as mentioned in #rokjarc's answer, you might want to add some parentheses for clarity, although these are not actually required:
if (menuPlayed && ([sender tag] == 0))

Change your code to:
if ((menuPlayed == TRUE) && ([sender tag] == 0))
And you'll probably have to typecast sender, something like
if ((menuPlayed == TRUE) && ([(UIButton *)sender tag] == 0))
Ofcourse you shouldn't just use (UIButton *) for typecast.
Use the correct class of your sender object or use one
of it's ancestor classes. I believe 'tag' is added to
UIView in this object hierarchy.

Related

Objective-C && doesn't short circuit for !var

Try running this:
UIView *testView = nil;
NSLog(#"Take 1");
NSString *message = #"view doesn't exist";
if (!testView && !testView.subviews) {
message = #"this message should never appear" ;
}
NSLog(message);
NSLog(#"Take 2");
message = #"view doesn't exist";
if (testView != nil && testView.subviews != nil) {
message = #"this message should never appear" ;
}
NSLog(message);
NSLog(#"Take 3");
message = #"view doesn't exist";
if (!testView) {
if (!testView.subviews) {
message = #"this message should never appear" ;
}
}
NSLog(message);
NSLog(#"Take 4");
message = #"view doesn't exist";
if (testView != nil) {
if (testView.subviews != nil) {
message = #"this message should never appear" ;
}
}
NSLog(message);
Output I get is:
Take 1
this message should never appear
Take 2
view doesn't exist
Take 3
this message should never appear
Take 4
view doesn't exist
Why doesn't Obj-C short circuit for !testView (in Take 1)?
Why does it go into !testView when testView is clearly nil in Take 3?
Should I not be testing the function of a nil object (e.g. when I test for subviews)?
The output you see is correct and the short-circuit behavior is working correctly too.
When boolean expressions are evaluated the result is considered to be true if the expression is not 0 or false if it is 0. So everywhere where you have if (something) you can read this as if (something != 0). The ! operator is the negation, so if you expand it you get the following for your first case: !(testView != 0) && !(testView.subviews != 0). The double negation can be removed and you get (testView == 0) && (testView.subviews == 0) which obviously is true (nil is 0 too).
There the short-circuiting is also correctly applied, you just can't see it. To prove that you could use a little wrapper function for your tests:
id testFunc( id value ) {
NSLog(#"testFunc: %#", value );
return value;
}
And use that in your tests: if (!testFunc(testView) && !testFunc(testView.subviews))
To make it short, your assumptions about the boolean not operator ! are wrong. It goes into if (!testView) because testView is nil.
There's nothing strange going on here. I rewrote your code, substituting testView for nil and testView.subviews for nil (messages to nil return nil).
NSLog(#"Take 1");
NSString *message = #"if clause was false";
if (!nil && !nil) { // if(true && true)
message = #"if clause was true" ;
}
NSLog(message); // outputs "if clause was true"
NSLog(#"Take 2");
message = #"if clause was false";
if (nil != nil && nil != nil) { // if (false && false)
message = #"if clause was true" ;
}
NSLog(message); // outputs "if clause was false"
NSLog(#"Take 3");
message = #"if clause was false";
if (!nil) { // if (true)
if (!nil) { // if (true)
message = #"if clause was true" ;
}
}
NSLog(message); // outputs "if clause was true"
NSLog(#"Take 4");
message = #"if clause was false";
if (nil != nil) { // if (false)
if (nil != nil) { // if (false)
message = #"if clause was true" ;
}
}
NSLog(message); // outputs "if clause was false"
If you want to know if the view exists, you can use something like:
if (testView) {
NSLog(#"View exists a.k.a. testView != nil");
} else {
NSLog(#"View doesn't exist a.k.a. testView == nil");
}
I'd recommend just using if (testView) and if (!testView) to check for the existence of objects. This is the standard in the Objective-C community and reads more clearly.

Annoying "expression result unused" warning

This is for a stupidly simple animation but I keep getting this annoying "expression result unused" warning. Code is as follows:
-(IBAction)thingOneTapped:(UIGestureRecognizer *)sender{
if ((isLevel = YES)) {
thingOneEnded = YES;
goingToThingOne = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(otherThingToOne) userInfo:nil repeats:YES];
x = 11;
y = 118;
}
else (isLevel = NO); {
[self viewDidLoad];
}
}
-(void)otherThingToOne{
if ((isLevel = YES) && (isLevelOne = YES)) {
if ((x > 0) && (y > 0)) {
otherThing.center = CGPointMake(otherThing.center.x - .5, otherThing.center.y - 5.35);
x = x - .5;
y = y - 5.35;
}
else ((x < 0) && (y < 0)); {
[self levelOneDefault];
// EVIL WARNING IS RIGHT HERE IN THE ELSE PART
}
}
For checking equality you need to use == (i.e. Two equals signs) that's why you're getting the error. Also, your code will not work as you expect at the moment.
As mentioned by others.
Instead of using if(someBool == YES) just use if(someBool). And instead of if(someBool == NO) just use if(!someBool).
The reason it will not work at the moment is because (I think but not 100% on this) if(someBool = NO) will first set someBool to NO and then evaluate the condition which will always be if(NO) which will never enter the of block.
I think. But not sure about this as I haven't tested it.
You can also use like that without checking == operator, also it will be more faster:-
if ((isLevel) && (isLevelOne))

Can't validate null string in Objective-C

I have the following code:
NSString *content = [[NSUserDefaults standardUserDefaults] stringForKey:#"mykey"];
NSLog(#"string is %#",content);
if ([content stringIsEmpty]){
NSLog(#"empty string");
}else{
NSLog(#"string is not empty");
}
stringIsEmpty is class category on NSString:
- (BOOL ) stringIsEmpty {
if ((NSNull *) self == [NSNull null]) {
return YES;
}
if (self == nil) {
return YES;
} else if ([self length] == 0) {
return YES;
}
return NO;
}
The output is:
string is (null)
string is not empty
How could it be null and not empty at the same time?
What happens is that:
[content stringIsEmpty:YES]
will return false (NO), when content is nil. So your code will take the
NSLog(#"string is not empty");
branch. This would be better:
if (content && [content stringIsEmpty:YES]){
...
A better way of doing this would be reversing the semantics of the method:
if ([content stringIsNotEmpty]) {
this would work finely because when content is nil it would return NO, when it is not nil, it would execute your method.
EDIT:
In Objective-C, sending a message to nil is legal and by definition will evaluate to nil. Google for "objective c sending message to nil".
In another language (C++), your code would crash (actually undefined behaviour, but to make things simple).
I use a small function to test for emptiness. It works on more than just strings:
static inline BOOL isEmpty(id thing) {
return thing == nil
|| ([thing respondsToSelector:#selector(length)]
&& [(NSData *)thing length] == 0)
|| ([thing respondsToSelector:#selector(count)]
&& [(NSArray *)thing count] == 0);
}
I usually import it in my pch file - you can see it along with attribution: https://gist.github.com/325926
As #sergio has already pointed out - when your string is nil you can't send it messages that test it for nil-ness - as sending messages to nil will do nothing for void methods, and return nil where the method returns something.
also
you are calling your method with a parameter
if ([content stringIsEmpty:YES])
but your method declaration doesn't take one:
- (BOOL ) stringIsEmpty {
What's that all about?
You have to check for the 'content == nil' case outside of the method.
If you want to be able to call just one method, change the method to something that tests for a positive, such as "stringHasContent", returning YES if self.length > 0.

Bool function for xcode

I am practicing some bool functions and I seem to be stuck any help will be appreciated. I must be making some little mistake.
-(BOOL) checkForWin
{
if ([[dictionary valueForKey:[cowsShuffled objectAtIndex:cowsCard]] intValue] == 2{
return YES;
}
}
-(void) moo
{
if (checkForWin == YES) {
NSLog (#"foo");
}
}
You need to call the method (not function), and you don't need to compare to YES. The if statement does that implicitly:
if ([self checkForWin]) …
Also note that checkForWin has a problem: it doesn't return anything if the if statement fails. It should be simply:
- (BOOL)checkForWin{
return [[dictionary valueForKey:[cowsShuffled objectAtIndex:cowsCard]] intValue] == 2;
}
Footnote: Strictly speaking, if (x) … isn't exactly the same as if (x == YES) …. It's actually closer to if (x != NO) …, but of course that's the same thing for most intents and purposes (and those for which it isn't are largely pathological).
Your method call is wrong. You call a method like this: [object method].
In your case [self checkForWin].

Cell data doesn't update

I'm going through some tutorial for editing table cells whose data is stored in a server. Everything is working fine - I can edit a table cell and click on the "save" button, but if I go back to the table overview it's not updated.
I've got 3 table fields:
titleField
authorField
atextField
I don't know if the problem comes from this piece of code, but I suppose so. The tutorial example has just 2 fields, and I need 3 fields, but I don't know how to implement this piece of code for 3 textfields:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
if (textField == titleField) {
[authorField becomeFirstResponder];
}
if (titleField == authorField) {
[self save];
}
return YES;
}
I already tried if (titleField == authorField == atextField), but the error message says: Comparison between pointer and integer ('int' and 'UITextField'). I also tried if (titleField == authorField && titleField == atextField && authorField == atextField){and I don't get an error, but it doesn't change the fact that the data doesn't update the changes.
How should the code above look like?
Those IF's dont have sense, you cannot do this:
if (titleField == authorField == atextField)
Because you are comparing the result of the first == with the textfield, hence the Comparison between pointer and integer error.
In the 2nd one,
if (titleField == authorField && titleField == atextField && authorField == atextField)
This is never going to get called, because the titleField cannot be 3 things at the same time.
My first thought would be doing something like this:
if (textField == titleField) {
[authorField becomeFirstResponder];
}
else if ((textField == authorField){
[atextField becomeFisrtResponder];
else if (titleField == atextField) {
[self save];
}
I think this is what you want to do.