What's really happen here? - objective-c

if ([self errorIsServerError:error] || [self errorIsBadRequest:error] || [self errorIsNetworkError:error]) {
return YES;
}
The methods errorIsServerError:, errorIsBadRequest:, and errorIsNetworkError: all return the BOOL YES or NO.
But I don't understand the syntax. Is it:
if (YES || YES || YES) { return YES; }
?

|| is the equivalent to saying 'or'. So your code is returning true if any of the values are true. This is what it's saying :
if ([self errorIsServerError:error] or [self errorIsBadRequest:error] or [self errorIsNetworkError:error])
If any of those are true then
{
return YES;
}

Each of those returns YES if that particular categorization applies to the given error. If the error is a server or network error, or a bad request, the method will return YES.
You could look at it like this:
if ([self errorIsServerError:error]) {
// The error is a server error
return YES;
} else if ([self errorIsBadRequest:error]) {
// The error is a bad request
return YES;
} else if ([self errorIsNetworkError:error]) {
// The error is a network error
return YES;
}
In either case, it will return yes if the error is any of those types. It will also return YES if it is two or all of those types (|| is the logical (inclusive) "or" operator).
If it's none of the types, your method will continue until it hits another return statement.

It's not really clear what you're asking, but in general, you're probably expecting none of those errors to come through, meaning this if condition will evaluate false and your program can go on its way.

Related

How to implement GKState's isValidNextState in Objective C

It seems that all of the examples for GameplayKit are always in Swift. I've decided not to move over to swift for now and I've just been translating a lot of code into Objective C, which is fine most of the time.
I'm trying to implement the isValidNextState method from the GKState class, but I'm getting an error for the switch statement and I'm not sure what it wants...it seems in Swift this is fine, but not in obj C. The error that I'm getting is:
Error: Statement requires expression of integer type('__unsafe_unretained Class _Nonnull' invalid
What should I have in the switch statement instead of stateclass?
-(BOOL) isValidNextState:(Class)stateClass {
switch (stateClass) { //ERROR ON THIS LINE
case [InvulnerableState class]: //not sure what this should be either
return YES;
break;
default:
break;
}
return NO;
}
Here's the equivalent in Swift which works fine:
override func isValidNextState(stateClass: AnyClass) -> Bool {
switch stateClass {
case is InvulnerableState.Type:
return true
default:
return false
}
}
Your isValidNextState method should be:
- (BOOL)isValidNextState:(Class)stateClass {
return stateClass == [InvulnerableState class];
}
And if you have multiple next valid states, it should be, for example:
- (BOOL)isValidNextState:(Class)stateClass {
return stateClass == [InvulnerableState class] ||
stateClass == [InvulnerableState2 class];
}

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].

correct way to send messages to (id *) variables or with (id *) arguments

I have a Core Data validation method I wrote that will not compile. I can modify the method so it compiles... but then I get runtime errors. The two versions of the method are below (notice the missing '*' in the second version). This version compiles but gives the runtime error "+[NSCFNumber doubleValue]: unrecognized selector sent to class 0x7fff70a448e8":
- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
if ( *value == nil ) {
return YES;
}
if ( [*value doubleValue] < 0.0 ) {
return NO;
}
return YES;
}
This version gives compiler warnings and errors (see warnings and errors below):
- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
if ( value == nil ) {
return YES;
}
if ( [value doubleValue] < 0.0 ) {
return NO;
}
return YES;
}
compiler errors and warnings:
warning: Semantic Issue: Receiver type 'id *' is not 'id' or interface pointer, consider casting it to 'id'
warning: Semantic Issue: Method '-doubleValue' not found (return type defaults to 'id')
error: Semantic Issue: Invalid operands to binary expression ('id' and 'double')
I finally figured that the problem may be in the calling code:
- (void)setInitialValue:(NSNumber *)initialValue {
[self willChangeValueForKey:#"initialValue"];
[self validateValue:initialValue forKey:#"initialValue" error:nil];
[self setPrimitiveInitialValue:initialValue];
[self didChangeValueForKey:#"initialValue"];
}
I changed the caller to use an '&' before initialValue and used the first version of the method, and everything worked. So the new calling code has the one line changed to be this:
[self validateValue:&initialValue forKey:#"initialValue" error:nil];
But is it really necessary to have the '&'?? setPrimitiveInitialValue doesn't use the '&'. I feel like my understanding of Objective-C is just not developed enough yet and all you gurus out there will find this a trivial question with a very straight forward answer.
id itself represents a pointer. So when you use id * you are actually referring to a pointer-to-a-pointer. The first part of this excellent tutorial explains this concept.
Chances are, this is what you are looking for:
- (BOOL)validateInitialValue:(id)value error:(NSError **)error {
if ( value == nil ) {
return YES;
}
if ( [value doubleValue] < 0.0 ) {
return NO;
}
return YES;
}
You're right that the problem is the calling code. id * indicates a pointer to an id value. An object variable by itself is an id, so you want a pointer to that variable, which is what you get with the &.
The reason you pass a pointer is so that, if your validation method knows of a way to modify the value to make it valid, it can return YES and also return the valid object (by setting the variable). So, for example, if numbers less than 1 should be clamped to 0, you might do:
- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
if ( *value == nil ) {
return YES;
}
if ( [*value doubleValue] < 0.0 ) {
return NO;
}
if ( [*value doubleValue] > 0.0 && [*value doubleValue] < 1.0 ) {
*value = [NSNumber numberWithInt:0];
}
return YES;
}
setPrimitiveValue: doesn't need to set variables in the calling context, so it just takes an id. (Very few methods work like validateValue:forKey:error:. Generally, they'll do it that way if they want to return a BOOL to indicate whether they changed something, but they still need a way to return the changed value as well.)

'If' conditional works with NSLog but not without? Objective-C

I hope this question is some what self explanatory.
This works, returns YES and NO: note the NSLog()'s
- (BOOL)dateTestCourse:(NSDictionary *)listing {
BOOL result = ([self exammpleTest] == 0) ? YES : NO;
if (result) {
NSLog(#"Passes Test");
return YES;
}
NSLog(#"Failed Test");
return NO;
}
But below always return YES? Only difference is no NSLog();
- (BOOL)dateTestCourse:(NSDictionary *)listing {
BOOL result = ([self exammpleTest] == 0) ? YES : NO;
if (result) {
// NSLog(#"Passes Test");
return YES;
}
// NSLog(#"Failed Test");
return NO;
}
Is this something to do with C? I have no idea? I might expect it always to return NO (if I shouldn't be breaking in the conditional), but surely that would return YES.
I know I should be returning result in the above examples, but I'm curious to know why.
These two blocks of code should be running the same. Are you perhaps doing a find/replace all on NSLog? That could be causing issues elsewhere, say with the exammpleTest(sic) method.
Also, the ternary operator on the second line is redundant, consider reducing that line to:
BOOL result = ([self exammpleTest] == 0);