2015-10-27 7 views
0

Я проверяю, нет ли массива в нуле, и если я хочу установить некоторую переменную счетчика в 0 и длину массива, если массив не равен нулю.Objective C trernary operator vs if statements nil check

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, а не в тройном операторе?

+0

Проверьте, что вы написали. «If» и «:» делают то же самое, поэтому что-то изменилось, когда вы изменили свой код. То, что вы описали, абсолютно невозможно на 100% с тем же self.someArray. – gnasher729

ответ

1

self.someArray является объектом NSNull, а не объектом NSArray.

Я подозреваю, что вы получили объект из сообщения JSON и не проверяли его тип, прежде чем хранить его в своем классе.

После того, как вы это отсортировали; это работает, если массив установлен или нет:

NSUInteger count = self.someArray.count; 
+0

Да, это сообщение JSON, установленное на 'null ', но проверка на nil в выражении if работает. Почему это? – somtingwong

+0

@somtingwong Потому что 'NSNull' не' nul'. Если вы ожидаете 'NSArray', тогда используйте' if ([thing isKindOfClass: [NSArray class]]) {...} '. – trojanfoe

+0

Но если 'NSNull! = Nil', то не следует ли ему удалять оператор else и все равно возвращать исключение, обращаясь к счету нулевого массива? – somtingwong

1

nil действительно (void *)0. NSNull - это класс, который имеет один экземпляр, который вы можете получить с помощью [NSNull null]. Юридически и безвредно отправлять сообщения в ноль, но нуль обмена сообщениями подвергается проверке типа времени выполнения.

Так что давайте инициализируем массив объекту NSNull. Любой код, который начинается этим путем, несомненно, вызывает печаль во время выполнения, но это именно то, что происходит, когда вы десериализация JSON (он должен сделать что-то с нулями, найденных в формате 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"); 

это последний бит интересно. Мы можем отправить сообщение count в массив nil без штрафа. Он отвечает 0, как будто массив пуст. Что действительно происходит, так это то, что мы можем отправить любое сообщение в nil, и результат всегда будет равен нулю.

А что делать с вашей проблемой? Одна из идей - принять, что self.array иногда может быть == [NSNull null] (что опять же не совпадает с == nil). Лучшее решение состоит в том, чтобы поймать состояние JSON-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;