Compare NSURL scheme in Swift with a String - objective-c

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.

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];
}

Checking to see if ObjectForKey exists [duplicate]

Most of the examples I found on the net write this:
if(x != nil)
// ...
Is there any problems with this?
if(x)
// ...
I tried both in a simple program and couldn't found any difference.
In Objective-C, nil is defined as a value called __DARWIN_NULL, which essentially evaluates to 0 or false in if-statements. Therefore, writing
if (x == nil) is the same as writing if (!x) and writing if (x != nil) is equal to if (x) (since comparing to false creates a negation, and comparing to true keeps the condition the same).
You can write your code either way, and it really depends on which you think is more readable. I find if (x) to make more sense, but it depends on your style.
It's like comparing if (someCondition == true) versus if (someCondition).
It all depends on you, and who's going to be reading the code.
Edit: As Yuji correctly mentions, since Objective-C is a superset of C, any condition that evaluates to a value other than 0 is considered to be true, and therefore, if someCondition in the example above were to evaluate to an integer value of, say, -1, comparing it to true would result in false, and the if-statement would not be evaluated. Something to be aware of.
Both
if (x != nil)
and
if ( x )
are equivalent, so pick the variant that in your opinion makes your code more readable for you (and others who will read and support your code)
Both are the same and this is a style question and it boils down to whether you prefer:
if (something) { ... }
versus
if (something != nothing) { ... }
I have always found #1 more clear but #2 is used extensively in documentation and hence the field so it is better to both know both forms and adapt to what a project uses and be stylistically consistent.
The best and safe way to check nil is
Make a common method, and add all these null :
+ (NSString *)trimWhiteSpaceAndNewLine:(NSString *)string {
NSString *stringSource = [NSString stringWithFormat:#"%#",string];
if ([stringSource isEqualToString:#"(null)"]) {
stringSource = #"";
return stringSource;
}
if ([stringSource isEqualToString:#"<null>"]) {
stringSource = #"";
return stringSource;
}
if ([stringSource isEqualToString:#"<nil>"]) {
stringSource = #"";
return stringSource;
}
if ([stringSource isKindOfClass:[NSNull class]]) {
stringSource = #"";
return stringSource;
}
if ([stringSource isEqualToString:#""]) {
stringSource = #"";
return stringSource;
}
if (stringSource == nil) {
stringSource = #"";
return stringSource;
}
NSString *stringFinal = [stringSource stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return stringFinal;
}
And check
NSString *strUuid = [Common trimWhiteSpaceAndNewLine:[dict valueForKeyPath:#"detail.uuid"]];
if (![strUuid isEqualToString:#""]) {
// do your stuff
}

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.

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

How to check if an NSDictionary or NSMutableDictionary contains a key?

I need to check if an dict has a key or not. How?
objectForKey will return nil if a key doesn't exist.
if ([[dictionary allKeys] containsObject:key]) {
// contains key
}
or
if ([dictionary objectForKey:key]) {
// contains object
}
More recent versions of Objective-C and Clang have a modern syntax for this:
if (myDictionary[myKey]) {
}
You do not have to check for equality with nil, because only non-nil Objective-C objects can be stored in dictionaries(or arrays). And all Objective-C objects are truthy values. Even #NO, #0, and [NSNull null] evaluate as true.
Edit: Swift is now a thing.
For Swift you would try something like the following
if let value = myDictionary[myKey] {
}
This syntax will only execute the if block if myKey is in the dict and if it is then the value is stored in the value variable. Note that this works for even falsey values like 0.
if ([mydict objectForKey:#"mykey"]) {
// key exists.
}
else
{
// ...
}
When using JSON dictionaries:
#define isNull(value) value == nil || [value isKindOfClass:[NSNull class]]
if( isNull( dict[#"my_key"] ) )
{
// do stuff
}
I like Fernandes' answer even though you ask for the obj twice.
This should also do (more or less the same as Martin's A).
id obj;
if ((obj=[dict objectForKey:#"blah"])) {
// use obj
} else {
// Do something else like creating the obj and add the kv pair to the dict
}
Martin's and this answer both work on iPad2 iOS 5.0.1 9A405
One very nasty gotcha which just wasted a bit of my time debugging - you may find yourself prompted by auto-complete to try using doesContain which seems to work.
Except, doesContain uses an id comparison instead of the hash comparison used by objectForKey so if you have a dictionary with string keys it will return NO to a doesContain.
NSMutableDictionary* keysByName = [[NSMutableDictionary alloc] init];
keysByName[#"fred"] = #1;
NSString* test = #"fred";
if ([keysByName objectForKey:test] != nil)
NSLog(#"\nit works for key lookups"); // OK
else
NSLog(#"\nsod it");
if (keysByName[test] != nil)
NSLog(#"\nit works for key lookups using indexed syntax"); // OK
else
NSLog(#"\nsod it");
if ([keysByName doesContain:#"fred"])
NSLog(#"\n doesContain works literally");
else
NSLog(#"\nsod it"); // this one fails because of id comparison used by doesContain
Using Swift, it would be:
if myDic[KEY] != nil {
// key exists
}
Yes. This kind of errors are very common and lead to app crash. So I use to add NSDictionary in each project as below:
//.h file code :
#interface NSDictionary (AppDictionary)
- (id)objectForKeyNotNull : (id)key;
#end
//.m file code is as below
#import "NSDictionary+WKDictionary.h"
#implementation NSDictionary (WKDictionary)
- (id)objectForKeyNotNull:(id)key {
id object = [self objectForKey:key];
if (object == [NSNull null])
return nil;
return object;
}
#end
In code you can use as below:
NSStrting *testString = [dict objectForKeyNotNull:#"blah"];
For checking existence of key in NSDictionary:
if([dictionary objectForKey:#"Replace your key here"] != nil)
NSLog(#"Key Exists");
else
NSLog(#"Key not Exists");
Because nil cannot be stored in Foundation data structures NSNull is sometimes to represent a nil. Because NSNull is a singleton object you can check to see if NSNull is the value stored in dictionary by using direct pointer comparison:
if ((NSNull *)[user objectForKey:#"myKey"] == [NSNull null]) { }
Solution for swift 4.2
So, if you just want to answer the question whether the dictionary contains the key, ask:
let keyExists = dict[key] != nil
If you want the value and you know the dictionary contains the key, say:
let val = dict[key]!
But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:
if let val = dict[key] {
// now val is not nil and the Optional has been unwrapped, so use it
}
I'd suggest you store the result of the lookup in a temp variable, test if the temp variable is nil and then use it. That way you don't look the same object up twice:
id obj = [dict objectForKey:#"blah"];
if (obj) {
// use obj
} else {
// Do something else
}
if ([MyDictionary objectForKey:MyKey]) {
// "Key Exist"
}
As Adirael suggested objectForKey to check key existance but When you call objectForKeyin nullable dictionary, app gets crashed so I fixed this from following way.
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;
if (dictionary && (object != [NSNull null])) {
self.name = [dictionary objectForKey:#"name"];
self.age = [dictionary objectForKey:#"age"];
}
return self;
}
if ( [dictionary[#"data"][#"action"] isKindOfClass:NSNull.class ] ){
//do something if doesn't exist
}
This is for nested dictionary structure