How can I check if an object in an NSArray is NSNull?
Asked Answered
P

9

71

I am getting an array with null value. Please check the structure of my array below:

 (
    "< null>"
 )

When I'm trying to access index 0 its crashing because of

-[NSNull isEqualToString:]: unrecognized selector sent to instance 0x389cea70

Currently its crashing because of that array with a crash log:

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull isEqualToString:]: unrecognized selector sent to instance 0x389cea70'
*** First throw call stack:
(0x2d9fdf53 0x3820a6af 0x2da018e7 0x2da001d3 0x2d94f598 0x1dee57 0x1dfd31 0x302f598d 0x301a03e3 0x3052aeed 0x3016728b 0x301659d3 0x3019ec41 0x3019e5e7 0x30173a25 0x30172221 0x2d9c918b 0x2d9c865b 0x2d9c6e4f 0x2d931ce7 0x2d931acb 0x3262c283 0x301d3a41 0xabb71 0xabaf8)
libc++abi.dylib: terminating with uncaught exception of type NSException
Purplish answered 27/9, 2013 at 20:6 Comment(3)
Please post the code where the array is created and objects are added.Savoyard
values are taken from a plistPurplish
Sue your backend developer for giving you Null.Shankle
M
127
id object = myArray[0];// similar to [myArray objectAtIndex:0]

if(![object isEqual:[NSNull null]])
{
    //do something if object is not equals to [NSNull null]
}
Marilumarilyn answered 27/9, 2013 at 20:17 Comment(4)
if you want to check for NSString use [object isKindOfClass:[NSString class]] before calling [object isEqualToString:];Marilumarilyn
ok i got the answer,now am adding only good values to array rejecting all un necesary nulls..lol thanks alotPurplish
No, don't use isEqual. For example if object in this case is a UIPrintPaper object, you'll get an exception because its isEqual implementation sends the NSNull class an unexpected selector.Caballero
if myArray does equal to NSNull, myArray[0] will crash?Condenser
J
31
if (myArray != (id)[NSNull null])

OR

if(![myArray isKindOfClass:[NSNull class]]) 
Jupiter answered 27/9, 2013 at 20:18 Comment(4)
but here array's first index is null not the entire arrayPurplish
ok i got the answer,now am adding only good values to array rejecting all un necesary nulls..lol thanks alot one upvote for your effortPurplish
NSNull is a singleton object so you can compare directly to [NSNull null].Frederiksberg
You are checking whether the Array is [NSNull null], not whether an object within that array is [NSNull null].Suazo
R
14

Building off of Toni's answer I made a macro.

#define isNSNull(value) [value isKindOfClass:[NSNull class]]

Then to use it

if (isNSNull(dict[@"key"])) ...
Reparation answered 22/4, 2014 at 15:37 Comment(2)
NSNull is a singleton object so you can compare directly to [NSNull null].Frederiksberg
I like this. It seems like we should have a few of these for common cases also, for stuff like BOOLAsString or StringFromBOOLVisa
V
9

Awww, guys. This is an easy one.

// if no null values have been returned.
if ([myValue class] == [NSNull class]) {
    myValue = nil;
}

I'm sure there are better answers, but this one works.

Visa answered 11/11, 2015 at 22:56 Comment(0)
R
7

I found the code for working with NSNull has the following problems:

  • Looks noisy and ugly.
  • Time consuming.
  • Error prone.

So I created the following category:

@interface NSObject (NSNullUnwrapping)

/**
* Unwraps NSNull to nil, if the object is NSNull, otherwise returns the object.
*/
- (id)zz_valueOrNil;

@end

With the implementation:

@implementation NSObject (NSNullUnwrapping)

- (id)zz_valueOrNil
{
    return self;
}

@end

@implementation NSNull (NSNullUnwrapping)

- (id)zz_valueOrNil
{
    return nil;
}

@end

It works by the following rules:

  • If a category is declared twice for the same Class (ie singleton instance of the Class type) then behavior is undefined. However, a method declared in a subclass is allowed to override a category method in its super-class.

This allows for more terse code:

[site setValue:[resultSet[@"main_contact"] zz_valueOrNil] forKey:@"mainContact"];

. . as opposed to having extra lines to check for NSNull. The zz_ prefix looks a little ugly but is there for safety to avoid namespace collisions.

Rikkiriksdag answered 17/4, 2015 at 6:49 Comment(3)
@gnasher729 Ha ha, up to you ;)Rikkiriksdag
The problem with this is that even though it is clever, it's not clear how it works to someone who is not you unless you comment it heavily and then people get used to it. Every cycle developers spend thinking, "Whhhat?," are cycles they aren't spending solving problems.Visa
Is it better to create one category that encapsulates the complexity, or have each developer write their own style of boiler-plate, error-prone code? Spending cycles solving the same problem over and over? The documentation for that method only requires a few lines. Provides something similar to how optional types work in other languages. Personally i like avoid ugly error prone, noisy nested if blocks, however if it works better in your context to write them out then do so.Rikkiriksdag
O
4

You can use the following check:

if (myArray[0] != [NSNull null]) {
    // Do your thing here
}

The reason for this can be found on Apple's official docs:

Using NSNull

The NSNull class defines a singleton object you use to represent null values in situations where nil is prohibited as a value (typically in a collection object such as an array or a dictionary).

NSNull *nullValue = [NSNull null];
NSArray *arrayWithNull = @[nullValue];
NSLog(@"arrayWithNull: %@", arrayWithNull);
// Output: "arrayWithNull: (<null>)"

It is important to appreciate that the NSNull instance is semantically different from NO or false—these both represent a logical value; the NSNull instance represents the absence of a value. The NSNull instance is semantically equivalent to nil, however it is also important to appreciate that it is not equal to nil. To test for a null object value, you must therefore make a direct object comparison.

id aValue = [arrayWithNull objectAtIndex:0];
if (aValue == nil) {
    NSLog(@"equals nil");
}
else if (aValue == [NSNull null]) {
    NSLog(@"equals NSNull instance");
    if ([aValue isEqual:nil]) {
        NSLog(@"isEqual:nil");
    }
}
// Output: "equals NSNull instance"

Taken from https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/NumbersandValues/Articles/Null.html

Orthochromatic answered 15/5, 2018 at 3:2 Comment(0)
S
3

A lot of good and interesting answers have been given already and (nealry) all of them work.

Just for completion (and the fun of it):

[NSNull null] is documented to return a singleton. Therefore

if (ob == [NSNull null]) {...} 

works fine too.

However, as this is an exception I don't think that using == for comparing objects is a good idea in general. (If I'd review your code, I'd certainly comment on this).

Suazo answered 13/10, 2016 at 7:39 Comment(0)
L
2

In Swift (or bridging from Objective-C), it is possible to have NSNull and nil in an array of optionals. NSArrays can only contain objects and will never have nil, but may have NSNull. A Swift array of Any? types may contain nil, however.

let myArray: [Any?] = [nil, NSNull()] // [nil, {{NSObject}}], or [nil, <null>]

To check against NSNull, use is to check an object's type. This process is the same for Swift arrays and NSArray objects:

for obj in myArray {
    if obj is NSNull {
        // object is of type NSNull
    } else {
        // object is not of type NSNull
    }
}

You can also use an if let or guard to check if your object can be casted to NSNull:

guard let _ = obj as? NSNull else {
    // obj is not NSNull
    continue;
}

or

if let _ = obj as? NSNull {
    // obj is NSNull
}
Lanford answered 29/2, 2016 at 20:42 Comment(0)
N
2

Consider this approach:

Option 1:

NSString *str = array[0];

if ( str != (id)[NSNull null] && str.length > 0 {
    // you have a valid string.
} 

Option 2:

NSString *str = array[0];
str = str == (id)[NSNull null]? nil : str;

if (str.length > 0) {
   // you have a valid string.
} 
Nephrectomy answered 28/7, 2017 at 9:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.