7

This in-Xcode documentation for NSNotFound is quite confusing:

It says "Available in iOS 2.0 through 8.4" and "Availability: iOS 8.1 to 8.0". So... Is it available before 8.0? Or in 9.0+? Also, what's going on here, if it is?

JAL
  • 41,701
  • 23
  • 172
  • 300
Ky -
  • 30,724
  • 51
  • 192
  • 308
  • Ever found out? Or just tried see how it behaves on different versions? The current documentation now says `Availability (8.0 to 8.0)`. – Alex Feb 17 '16 at 10:06
  • 1
    @Alex I haven't. It seems it's working fine in at least iOS 7.2 to 9.2.1, since that's who our app supports. – Ky - Feb 17 '16 at 16:11
  • 1
    Seems to work fine for me as well from iOS 7.0 to 9.2.1. Weird. – Alex Feb 18 '16 at 12:52
  • 4
    I'd recommend submitting a documentation bug to [Apple](http://bugreport.apple.com) . – diatrevolo Feb 18 '16 at 18:16

2 Answers2

7

Insert availabilityOfNSNotFound == NSNotFound joke here.


At some point when Apple was pushing mandatory 64-bit device support (iOS 8.4 SDK?), the declaration of NSNotFound was changed from:

enum {NSNotFound = NSIntegerMax};

to

static const NSInteger NSNotFound = NSIntegerMax;

You can verify this in <Foundation/NSObjCRuntime.h>.

The documentation was never changed, so the availability of the enum NSNotFound is no longer in the SDK. But as of iOS 9 and above, the static const NSInteger NSNotFound is available.

Although I cannot answer the true availability of NSNotFound since I don't work for Apple (as a developer I think it's safe to use in all iOS versions since 2.0, or else a lot of Foundation classes would break since they can return NSNotFound), you can check to see if the memory location for NSNotFound is NULL:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-compare"
BOOL found = (&NSNotFound != NULL);
#pragma clang diagnostic pop
if (found) {
    NSLog(@"meh");
}
JAL
  • 41,701
  • 23
  • 172
  • 300
1

I realized that NSNotFound is a static constant, and so it shouldn't matter what OS the device has, as the value shouldn't change after compilation.

To confirm this, I made the simplest file I could and looked at its compiled assembly (without optimizations):

Left: original C source code. Right: LLVM assembly output.

An illustration showing NSNotFound is replaced with its absolute value at compile time

As you can see, NSNotFound is replaced with its absolute value, in this case 0x7fffffffffffffff since this is a 64-bit compilation. For 32-bit compilations, it would be 0x7fffffff.

This is awesome. It means that, as long as it compiles, it will work (assuming Apple never changes the value of NSNotFound)!

While this doesn't explain the strange documentation, it does provide some reassurance that it should work on all versions of iOS.

Ky -
  • 30,724
  • 51
  • 192
  • 308
  • You really shouldn't use a hardcoded value instead of the constant. The constant is exposed like this for a reason! Additionally, the value is assigned to `NSIntegerMax`, which expands to `LONG_MAX`, which could potentially be platform-dependent. – JAL Feb 18 '16 at 17:43
  • @JAL I think you're misunderstanding me. I'm using the constant! The left pane is the C code, and the right pane is the assembly output of the compiler. – Ky - Feb 18 '16 at 18:03
  • I'm not misunderstanding you. I just saying it's not safe to use either constant. – JAL Feb 18 '16 at 18:06
  • @JAL But you said "You really shouldn't use a hardcoded value instead of a constant." I'm not; I'm using the constant. – Ky - Feb 18 '16 at 18:08
  • I see, you're referring to the value after compilation. – JAL Feb 18 '16 at 18:09