Took over an old project. This project ran for six or seven years, and it was full of MRC autoreleases and some old writing methods. This bug is very simple. The client model field type is NSString, but in some cases, the server will return the NSNumber type, and the client will use this field to isEqualToString, so it will crash directly.

This is a problem we don’t usually encounter in normal projects… In a normal project, YYModel or some other Model will automatically convert data types for us. When I took over, it was natural to make changes…

NSString *type = [root objectForKey:@"type"]; NSString *type = [root objectForKey:@"type"];Copy the code
NSString * type = [NSString stringWithFormat:@"%ld",[[root objectForKey:@"type"] integerValue]];Copy the code

Since type is supposed to return @”0″, @”1″, @”2″ and so on, I’m forcing the type, and I think I’ve solved it. However, in the process of merging code Review, my colleague told me that it was risky to write in this way and might collapse, so HE suggested me to change it

Recommended modified code: NSString * type = [NSString stringWithFormat:@"%@",[root objectForKey:@"type"]];Copy the code

Huh??????? In years of writing code, I’ve never seen anything break like this. Later, I wrote a Demo to verify: test the code

- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor redColor]; [self doDataTestDemo]; } - (void)doDataTestDemo{ [self testDemo:nil]; [self testDemo:@"adsfsdfaf"]; [self testDemo:@(1)]; [self testDemo:@"a"]; [self testDemo:NULL]; [self testDemo:[NSNull null]]; } - (void) testDemo: (id) value {NSLog (@ "incoming value = % @", value); NSString *str1 = [NSString stringWithFormat:@"%@",value]; NSString *str2 = [NSString stringWithFormat:@"%ld",[value integerValue]]; If ([str1 isEqualToString: @ "1"]) {NSLog (@ "equals the str1 = % @", str1); }else{NSLog(@"str1 unequal =%@",str1); } the if ([str2 isEqualToString: @ "1"]) {NSLog (@ "str2 equal = % @", str2); }else{NSLog(@"str2 unequal =%@",str2); }}Copy the code
Console output 2021-04-15 17:52:43.030584+0800 TestDemo[1837:657964] Value =(NULL) 2021-04-15 17:52:43.030686+0800 Str1 Unequal =(NULL) 2021-04-15 17:52:43.030717+0800 TestDemo[1837-657964] UNEQUAL =0 2021-04-15 17:52:43.030744+0800 TestDemo[1837.657964] value=adsfsdfaf 2021-04-15 17:52:43.030818+0800 TestDemo[1837.657964] Str1 unequal = ADsfsdFAf 2021-04-15 17:52:43.030856+0800 TestDemo[1837:657964] STR2 unequal =0 2021-04-15 17:52:43.030885+0800 Str1 =1 2021-04-15 17:52:43.031024+0800 TestDemo[1837-657964] str1 =1 2021-04-15 17:52:43.031313+0800 TestDemo[1837.657964] STR2 Equal =1 2021-04-15 17:52:43.031356+0800 TestDemo[1837.657964] Value passed in = A 2021-04-15 17:52:43.031435+0800 TestDemo[1837:657964] str1 not equal =a 2021-04-15 17:52:43.031534+0800 TestDemo[1837:657964] str1 not equal =a 2021-04-15 17:52:43.031534+0800 TestDemo[1837:657964] Str2 not equal =0 2021-04-15 17:52:43.031681+0800 TestDemo[1837:657964] Value =(NULL) 2021-04-15 17:52:43.031926+0800 TestDemo[1837:657964] STR1 unequal =(NULL) 2021-04-15 17:52:43.032106+0800 [self testDemo:[NSNull null]] crashesCopy the code

Well, it does crash, because [NSNull null] returns an inherited NSObject object, so it definitely crashes. Report method not recognized

2021-04-15 18:00:52.223725+0800 TestDemo[1840:659292] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull integerValue]: unrecognized selector sent to instance 0x1f18ebad8'
Copy the code

It’s true that when the server returns null, the client might play snakeskin… But even with the NSString stringWithFormat:@”%@” method, projects can be riddled with (null) UI displays in scenarios where the server is unreliable. Of course we had many solutions, such as refactoring the code, switching the model to YYModel, classifying NSNull, runtime null, etc., but in the end we decided to leave it at that. Here, again, the difference between nil, nil, NULL, and [NSNull NULL] is rewritten

  • nil
    • When an object is nil, even though the memory address has been reclaimed. But we can still send messages to it without causing a crash.
  • Nil
    • It’s essentially the same thing as nil, it’s always null for objects, null for classes
  • NULL
    • C Speech product, null pointer
  • [NSNull null]
    • Essentially an object with a null value. It inherits from NSObject, and the difference is that it’s not a null pointer, it’s an object with a null value. Since it is an object, when a method that does not belong to it is called, it will Crash, which is why it crashed in this case.