0

im building a chart view and I'm giving it a datasource to which it can ask for a Y value that corresponds to a given X index. In some cases, there is no Y value for a given X index. I can't send nil in this circumstance, as 0 may be a perfectly valid Y value. What is the best way in objective C to communicate that there is No Value at all?

Sean Danzeiser
  • 9,141
  • 12
  • 52
  • 90

5 Answers5

3

It seems to me that you're sending the data between the model and the view using some sort of object, perhaps NSNumber, that's holding a value, and you are retrieving the value by sending it a message, and you know that if the object is nil, the message send will return 0.

That's correct. In this case, simply check if the object is nil, and proceed accordingly:

- (void)plotValue:(NSNumber *)number
{
    if (number == nil) {
        // no value
    } else {
        // Value may be 0, but you can now safely plot it.
    }
}
2

nil is not 0. They are different.

If you are using NSNumber, then nil is clearly disjoint from the set of NSNumber.

If you are using int, then you can't use nil.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 1
    Except in Objective-C++, where `nil` is `#define`d to `0`. –  Mar 15 '13 at 06:19
  • @H2CO3: It's defined to `__null`. – Dietrich Epp Mar 15 '13 at 06:22
  • 1
    @DietrichEpp keep following the #defines until you hit the root definition. Eventually, it's 0 or some cast of 0. – CodaFi Mar 15 '13 at 06:23
  • @DietrichEpp Follow the macro expansion. In turn, that's `__DARWIN_NULL` (or the alike), which is then just `0` if `__cplusplus` is defined, or `((void *)0)` if it isn't. –  Mar 15 '13 at 06:23
  • @H2CO3: I'm telling you, it's `__null`, even after all the macros are expanded. – Dietrich Epp Mar 15 '13 at 06:24
  • @CodaFi: No need to follow definitions, the preprocessor will do that for you. Because you didn't believe me, I hunted it down: it's defined to `__DARWIN_NULL` in `objc/objc.h`, which is defined to `__null` in `sys/_types.h`. – Dietrich Epp Mar 15 '13 at 06:26
  • `__null` must be some compiler built-in value or something, it has the double underscore which is reserved for implementations. – dreamlax Mar 15 '13 at 06:27
  • @DietrichEpp I just looked it up in the iOS 5.1 sysroot, and it indeed is `__null`. It wasn't the case last time I looked at the definitions (4.x times). –  Mar 15 '13 at 06:28
  • __null is (I believe) 8 bytes of zeroes. – CodaFi Mar 15 '13 at 06:29
  • @CodaFi: Could you elaborate? That doesn't make sense to me. – Dietrich Epp Mar 15 '13 at 06:29
  • @H2CO3: That was before C++11 came out, and we need new compiler built-ins to support `nullptr` semantics. – Dietrich Epp Mar 15 '13 at 06:29
  • __null is what backs NULL in most languages. It's a system-defined value, but if I remember correctly, iOS says it's 8 bytes of zeroes. I could be wrong. – CodaFi Mar 15 '13 at 06:31
  • @CodaFi [You are wrong.](http://stackoverflow.com/questions/8783566/where-is-null-defined-in-g) –  Mar 15 '13 at 06:32
  • @CodaFi: It's like saying that `0` is four bytes of zeroes. It's a literal, so it doesn't *itself* use storage in the program. The resulting program may *encode* that value using some number of bytes, or more, or none. – Dietrich Epp Mar 15 '13 at 06:35
2

Don't use primitives in your data source, instead use NSNumber. Then you can differentiate between nil and an NSNumber storing the value 0.

Nick C
  • 645
  • 3
  • 6
1

If you don't want to use an object (NSNumber), you can return a negative number (if possible) or the maximum/minimum integer that is unlikely to be returned by the datasource.

Yariv Nissim
  • 13,273
  • 1
  • 38
  • 44
0

I'm assuming you're talking about some scalar like an NSInteger or something. If literally any integer is valid for the Y value, then there is no way to do this. However, most likely there is some practical range, so you can just choose some value outside this range to be "special". For example, Cocoa has the value NSNotFound, which NSArray will return if you ask for the index of an object that is not in the array. It is defined as the largest possible NSInteger. You could reuse this yourself if your Y value will never be NSIntegerMax.

The other option, assuming you don't want to create a special type just for this, would be to have your method return both Y and whether or not Y was actually found. For example, some rough pseudocode:

- (NSInteger)yForX:(NSInteger)x wasFound:(BOOL *)found {
    if (yWasFound) {
        if (found) 
            *found = YES;
        return y;
    } else {
        if (found)
            *found = NO;
        return 0;
    }
}

You could use NSNumber, as some have suggested, but I find it a little awkward to deal in NSNumbers just to get nil.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • 2
    I'd probably do it the other way around, return `BOOL` and have the method named `getYForX:`. Most methods with `get` in the name indicate caller-supplied buffers and also many methods with `get` in the name return `BOOL` indicating success or failure (if such a method could fail). – dreamlax Mar 15 '13 at 06:55