Testing equality to NSNull
Asked Answered
H

4

14

Below is a code block, that is supposed to test to see if a dictionary is null, and if it isn't, pull out the correct object. However, for some reason, despite the fact that the if check fails, the code still executes. Is there some quirk with how NSNull works that I don't understand, or is this an Apple bug?

if (svcUser && !(svcUser == (id)[NSNull null])) {
    return [svcUser objectForKey:@"access_level"];
}

Console response:

(lldb) print svcUser && !(svcUser == (id)[NSNull null])
(bool) $0 = false
(lldb) continue
-[NSNull objectForKey:]: unrecognized selector sent to instance 0x2b51678
Hedgehog answered 17/5, 2013 at 2:6 Comment(3)
Try breaking on exceptions, and make sure that the "unrecognized selector" is being thrown where you think it is developer.apple.com/library/mac/recipes/…Ias
Did you ever figure out what was going on here?Putup
The definitive explanation ---> nshipster.com/nilMaricamarice
B
33

Simply check for:

svcUser == [NSNull null]

This is the approach that Apple mentions in their docs.

Biconvex answered 3/12, 2013 at 15:36 Comment(1)
This gave me a warning, use https://mcmap.net/q/789929/-testing-equality-to-nsnull to suppress it.Collar
C
20

NSNull is a class. And like with all classes, you must use isEqual:, not == to see if two objects represent the same value.

if (svcUser && ![svcUser isEqual:[NSNull null]]) {
    return [svcUser objectForKey:@"access_level"];
}
Coycoyle answered 17/5, 2013 at 2:10 Comment(5)
Yes, but [NSNull null] is a singleton object, so you can check it either way, since they will be reference equal. As you can tell from the console output, the if logic is fine, but somehow the code block is still getting executed.Hedgehog
I feel like I've always used == successfully for NSNull. Apple's sample code seems to even endorse this comparison.Kongo
But that is an implementation detail you shouldn't count on. Using isEqual: is better and safer than relying on == working. This has burned a lot of people in the past when comparing NSString literals. @Hedgehog - just a sanity check but are you 100% sure that the crash is in the posted line of code and not elsewhere?Coycoyle
I wouldn't say it's an implementation detail given that it's documented to be a singleton. For the sake of consistency it may be best to go with isEqual: though, especially if you call it on [NSNull null] and not your own object. Speaking of implementation details, NSNull doesn't seem to override isEqual: currently, so I'm skeptical that replacing == with isEqual: would produce a different result at the present time - I suspect that you're spot on with the sanity check and that the code is crashing elsewhere.Kongo
That seems to conflict with the Apple documentation "To test for a null object value, you must therefore make a direct object comparison." developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…Dramaturgy
C
10

Using @JE42's approach gives me a warning as of Xcode 5.1. Instead cast it:

(id)svcUser == [NSNull null]
Collar answered 3/4, 2014 at 0:28 Comment(0)
S
8

You can check it by using:

 if(![svcUser isKindOfClass:[NSNull class]]){
    return [svcUser objectForKey:@"access_level"];
}
Siret answered 17/5, 2013 at 2:15 Comment(5)
If svcUser is actually an NSNull object, calling count on it will result in a crash. Also, the goal is to be sure it is not an NSNull object. And what is nsnull?Coycoyle
Also, using == to compare the two objects isn't correct. You need to use isEqual: to compare two objects.Coycoyle
sorry didn't noticed it. but already updated it. at first I thought you were looking checking if svcUser has value my badSiret
This is my favored method, as it does not require typecastingSucre
if (svcUser != nil && ![svcUser isEqualTo:[NSNull null]]), you should check nil, and checking NSNull is not enough.Mufinella

© 2022 - 2024 — McMap. All rights reserved.