How to implement GKState's isValidNextState in Objective C - 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];
}

Related

What's really happen here?

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.

Compare NSURL scheme in Swift with a String

I was wondering if this is possible to do in swift and what it would be the way of doing it?
I just want to be able to compare? the scheme of my url to whatever string I want.. This is how I have been doing it in objc.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if ([request.URL.scheme isEqual: #"http"] || [request.URL.scheme isEqual:#"https"]) {
return NO;
}
return YES;
}
Use == in Swift instead of isEqual: or isEqualToString: in Objective-C
if (request.URL.scheme == "http" || request.URL.scheme == "https") {
Really Swifty:
if let scheme = request.URL.scheme {
switch scheme {
case "http", "https":
return true
default:
return false
}
}
Essentially, safely pull the scheme from the URL (could be nil after all) and then switch on it (which you can do in Swift but not Objective-C) using compound case statements.
The other 2 answers will fail if the source URL doesn't have the scheme in lowercase (i.e., hTTp://…).
Also, the other 2 answers fail to unwrap the optionals (request.URL?.scheme?).
Here's another option:
if let lowercaseScheme = request.URL?.scheme?.lowercaseString {
if lowercaseScheme.rangeOfString("http") != nil {
println("It's a match!")
}
}
Or, in Swift 1.2 (Xcode 6.3):
if let lowercaseScheme = request.URL?.scheme?.lowercaseString where lowercaseScheme.rangeOfString("http") != nil {
println("It's a match!")
}
Or, if you don't need to actually know the scheme inside the block:
if request.URL?.scheme?.lowercaseString.rangeOfString("http") != nil {
println("It's a match!")
}
This will match http, https, and hTTpS. It will also match lolHTTProfl. If that's not okay in your use case, use the above answer's approach (the == operator), but with optional unwrapping and lowercaseString.

Objective-C to Swift

How can I do this in Swift?
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
NSLog(#"UIGestureRecognizerStateEnded");
//Do Whatever You want on End of Gesture
}
else if (sender.state == UIGestureRecognizerStateBegan){
NSLog(#"UIGestureRecognizerStateBegan.");
//Do Whatever You want on Began of Gesture
}
}
I don't know how to transform that sender declaration in Swift. Thanks!
It's essentially the same code -- a function that checks the value of the parameter's state property:
func handleLongPress(gestureRecognizer: UILongPressGestureRecognizer) {
switch gestureRecognizer.state {
case .Began:
println("UIGestureRecognizerState.Began")
case .Ended:
println("UIGestureRecognizerState.Ended")
default:
break;
}
}
func handleLongPress (sender: UILongPressGestureRecognizer){
if sender.state == UIGestureRecognizerStateEnded {
println(UIGestureRecognizerStateEnded)
}else if (sender.state == UIGestureRecognizerStateBegan){
println(UIGestureRecognizerStateBegan)
}
}
try this. I just translated what you have written in obj-c

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);