What is nil but not nil when inserted into NSMutableDictionary

I ran into some strange behavior on iPhone 6, iOS 8.3.

appVersion is the passed NSString * parameter.

  NSLog(@"A:%@:%d",appVersion,(int)appVersion.length);
  if (!appVersion)
    NSLog(@"a");
  if (appVersion == 0)
    NSLog(@"b");
  if (appVersion == nil)
    NSLog(@"c");
  if (appVersion == NULL)
    NSLog(@"d");
  if (appVersion == Nil)
    NSLog(@"e");
  if ([appVersion isEqual:[NSNull null]])
    NSLog(@"f");

  NSString* av = [NSString stringWithFormat:@"%@",appVersion];
  if ([av isEqualToString:@"(null)"])
    NSLog(@"g");
  if (((int)appVersion) == 0)
    NSLog(@"h");

  if (appVersion) {
    NSLog(@"B:%@:%d",appVersion,(int)appVersion);
    params[@"appversion"] = appVersion;
  }

      

Release build failed:

A:(null):0
g
h
B:(null):0

      

and then fail ("object cannot be nil (key: appversion)").

Debug build returns:

a
b
c
d
e
g
h

      

What is zero but not zero?

+3


source to share


3 answers


I'm working on some legacy code and haven't noticed that there is a difference in method signature between .h and .m files.

The .h file has:

- (void) verifyWinner:(NSString*)baseAcctId
           appVersion:(NSString*)appVersion
           onComplete:(OnCompleteWinnerVerifier)onComplete __attribute__((nonnull));

      



I am assuming the original developer wanted onComplete to be set to zero. However, for whatever reason, __attribute__((nonnull))

binds to each of the parameters.

Because of the tag, __attribute__

Xcode will optimize all! = Nil checks for the release build, causing it to fail.

This issue only appeared with XCode 6.3. Thus, it is possible that Apple recently added optimization, otherwise there was a bug in 6.3 that binds __attribute__

with each of the parameters, and not just with the parameters that it is next to (for optimization purposes anyway).

+3


source


Check [NSNull null]

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



https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/NumbersandValues/Articles/Null.html

0


source


The result looks strange. There is a good article; google for "What Every Programmer Should Know About Undefined Behavior" by Chris Lattner (the lead developer of Swift, so he should know what he's talking about).

It looks like after the very first NSLog instruction, the optimizing compiler decided that appVersion cannot be nil, because passing nil to NSLog would be undefined. This explains why ae are not printed.

"h" is printed because appVersion is a 64-bit pointer, int is only 32-bit, so a non-nil conversion of appVersion to int could just result in zero. The optimizer cannot remove this check, even if it is sure that appVersion is not zero.

And since the compiler is sure that appVersion is not zero, the last test fails, appVersion is stored in param, and because it is zero, you fail.

0


source







All Articles