Objective C三元运算符vs if语句nil check

时间:2015-10-27 15:20:10

标签: ios objective-c nsarray

我正在检查数组是否为nil,如果是,我想将一些计数器变量设置为0,如果数组不是nil则设置为数组的长度。

NSUInteger count = 0;
if (self.someArray == nil) {
    count = 0;
}
else {
    count = self.someArray.count;
}

这正如预期的那样正常。但是,当我尝试做这样的事情时:

NSUInteger count = (self.someArray == nil) ? 0 : self.someArray.count

我收到[NSNull count] unrecognized selector错误。但是,当我这样做时

([self.someArray isKindOfClass:[NSNull class]]) ? 0 : self.someArray.count` 

看起来后者应该对我有用,但是有什么简单的我可以忽略吗? NSNull适用于零的对象?为什么简单的nil检查在if语句中而不是在三元运算符中工作?

2 个答案:

答案 0 :(得分:1)

self.someArrayNSNull个对象,而不是NSArray个对象。

我怀疑你从JSON消息中获取了对象,并且在将它存储到你的类之前没有检查过它。

一旦你排序了;如果数组已设置,则此方法有效:

NSUInteger count = self.someArray.count;

答案 1 :(得分:1)

nil真的是(void *)0NSNull是一个具有单个实例的类,您可以使用[NSNull null]获取该实例。将消息发送到nil是合法且无害的,但是消息传递null受运行时类型检查的影响。

因此,让我们将数组初始化为NSNull对象。任何以这种方式开始的代码肯定会在运行时引起悲伤,但这正是您反序列化JSON时所发生的事情(它必须在中找到带有空值的某些)。 ..

NSArray *array = (NSArray *)[NSNull null];  // evil cast, just to illustrate

if (array == 0)
    NSLog(@"I will never execute");
else
    NSLog(@"I will always execute.  null is a pointer to the instance of NSNull");

if ([array isKindOfClass:[NSNull class]]) // true, of course
if (array == [NSNull null]) // true, null is a singleton

if (!array)        // false, same as above
if (array == nil)  // false, same as above, array points to an object

NSLog(@"CRASH on next line, because null doesn't respond to count");
if (array.count > 0) // crash

但是,如果我们尝试从更为良性nil ...

开始的某些事情
NSArray *array = nil;
// or NSArray *array;  same thing, since compiler will init to 0x0 for you

if (array == 0)
    NSLog(@"I will always execute");
else
    NSLog(@"I will never execute");

if (!array)        // true, same as above
if (array == nil)  // true, of course

NSLog(@"No crash on next line");
if (array.count > 0)
    NSLog(@"I will never execute");

最后一点很有意思。我们可以将计数消息发送到nil数组而不会受到惩罚。它回答0,好像数组是空的。真正发生的是我们可以发送任何消息给nil,结果总是零。

那你该怎么办?一个想法是接受self.array有时可能是== [NSNull null](这又与== nil不同)。更好的解决方案是在赋值点捕获JSON-produce-NSNull条件,如此......

// I just finished deserializing some JSON to id someObject
self.someArray = (someObject.theArray == [NSNull null])? nil : someObject.theArray;

// anytime after, we can safely message the array
NSInteger theCount = self.someArray.count;  // zero, if someArray is empty OR nil
// and even get objects from it, as long as it contains any
id someObject = (self.someArray.count)? [someArray lastObject] : nil;