1

I am trying to populate an array by taking an existing array and removing nil values from it. The array was populated from a the JSON response of an http call. Sometimes the array has a null value at the end, and the easiest way to remove that value so I wouldn't have to handle it everywhere in my code would be to use NSArray's filteredArrayUsingPredicate: to assign the variable into the instance variable I use throughout my class.

NSArray *respAgencyList = (NSArray*) [JSON valueForKeyPath:@"xml.path.to.data" ];
NSLog(@"data before filter: %@", respAgencyList); 
// prints: ( { domain: "foo.com", name:"foobar"}, "<null>" });
if (respAgencyList != nil && respAgencyList.count > 0) {
    agencies = [respAgencyList filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
            NSLog(@"Evaluated object is %@", evaluatedObject); //prints <null> for the null value
            BOOL ret = evaluatedObject != nil;
            return ret;

        }]];
}

In the above code the return value is always YES. However, when I put the debugger on and step through it I see:

evaluatedObject = id 0x00000000

enter image description here

Isn't this a null/nil value? What is different about this value compared to nil?

jszumski
  • 7,430
  • 11
  • 40
  • 53
Matt Wolfe
  • 8,924
  • 8
  • 60
  • 77

2 Answers2

2

It is impossible for an NSArray to contain a nil element.

Some enumeration methods do hand you nil after the enumeration, as a signal that you've reached the end, but the nil is not in the array — it's just a signal, and you are not expected to do anything serious with it. However, I do not know whether this is one of them.

I suggest that instead of trying to remove nil from the array, which is impossible since nil was never there in the first place, you examine the array directly (log it, look in the debugger, whatever) and assure yourself that what you're trying to do is unnecessary.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Good point. But what is the solution to the problem. I actually did solve this but I thought it was a good question as very similar code would work fine in say Ruby. – Matt Wolfe Apr 15 '13 at 18:26
  • What is the solution to *what* problem, exactly? (And hey, this isn't Ruby, not by a long chalk.) – matt Apr 15 '13 at 18:27
  • Also you just asked me to inspect with a debugger, as I've done and put a screenshot of how the debugger shows the evaluatedObject passed to the block. – Matt Wolfe Apr 15 '13 at 18:27
  • No, I suggested you inspect the *array*. The screen shot is the evaluatedObject. – matt Apr 15 '13 at 18:28
  • In objective C I typically compare to nil and this was the first time I've seen it not work how I expected. I didn't realize you couldn't have nil values but you could have NSNull objects and that was what I needed to check for. – Matt Wolfe Apr 15 '13 at 18:36
  • 1
    No Objective-C collection can contain nil. It's not an object. That is what NSNull is to help with. http://www.apeth.com/iOSBook/ch10.html#_nsnull – matt Apr 15 '13 at 18:38
  • Just for the record, you told me to inspect the array, which isn't that exactly what I'm inspecting when I look at the block passed to filteredArrayUsingPredicate:. Also, ios dev is pretty new to me and I'm not aware of what the types are from the debugger so while I had looked at that originally I wasn't sure what the data actually was, it just looked like a null object which I thought was synonymous with nil. For example, i just made a variable and assigned to nil, and it points to 0x0000000 by default, the same thing the debugger shows a null value in my array. – Matt Wolfe Apr 15 '13 at 19:05
  • So while this may be super obvious to you it's not super obvious to me and the debugger doesn't make it obvious either. – Matt Wolfe Apr 15 '13 at 19:07
  • (1) I said inspect *in the debugger*. To inspect the array `respAgencyList` in the debugger, ask it to `po respAgencyList`. (2) Yes, `(id)0` is nil. But I do not know exactly what line you were on or what you were doing at the moment that screen shot was generated, so we still know nothing about exactly *why* you were seeing nil as the value of `evaluatedObject`; I did give you one theory as to why that might be but it was only a theory. Regardless, I tell you again that it is *impossible* that NSArray should contain nil. – matt Apr 15 '13 at 19:13
  • The variable name in the screenshot is named evaluatedObject which is the one passed into the block and should be pretty obvious. I never saw "nil" as the evaluated object, i just saw 0's and I thought that would be equal to nil in a comparison. I understand now and I appreciate you telling me that nil can't be in an NSArray and that certainly was a hint towards the answer. Thank you. – Matt Wolfe Apr 15 '13 at 19:19
  • 1
    @matt: you mean no collection that comes with Cocoa. I can easily write an Objective-C collection that allows `nil` – newacct Apr 16 '13 at 06:54
2

You should also check for NSNull, which can be placed into an NSArray since it is a proper object.

BOOL ret = (evaluatedObject != nil && [evaluatedObject isKindOfClass:[NSNull class]] == NO);
jszumski
  • 7,430
  • 11
  • 40
  • 53
  • I actually ended up using: return evaluatedObject != nil && evaluatedObject != (id) [NSNull null]; which worked fine, but this looks like it works the same. – Matt Wolfe Apr 15 '13 at 18:33
  • 1
    Yeah they'll work the same, but I always try to avoid a cast since it has the potential to cover up compiler warnings that might indicate a real problem. – jszumski Apr 15 '13 at 18:34