Использует ли Objective-C оценку короткого замыкания? - PullRequest
18 голосов
/ 14 января 2010

Я пробовал что-то вроде:

if(myString != nil && myString.length) { ... }

И получил:

- [Длина NSNull]: нераспознанный селектор отправлен в экземпляр

Разве Objective-C не закорачивается после сбоя первого условия?

Ответы [ 4 ]

30 голосов
/ 14 января 2010

Objective-C поддерживает оценку короткого замыкания, как и C.

Похоже, что в вашем примере myString равно NSNull, а не nil, поэтому myString != nil имеет значение true.

NSNull является одноэлементным и используется для представления nil, где разрешены только объекты, например, в NSArray.

Кстати, обычно люди пишут if (!myString && myString.length == 0). Сравнение с nil довольно безобразно. Кроме того, я бы сравнил длину с 0. Это кажется более ясным.

10 голосов
/ 14 января 2010

Objective-C является строгим надмножеством C.

Поскольку C поддерживает оценку короткого замыкания, Objective-C также делает это.

3 голосов
/ 14 января 2010

Как определяется NSNull? Если это объект, который должен ничего не представлять, то он не будет равен нулю. другими словами, NSNull и nil - это не одно и то же.

0 голосов
/ 14 января 2010

Если у вас где-то есть NSNull, вы, вероятно, используете JSON-анализатор или CoreData. Если число в CoreData не установлено, CoreData вернет вам NSNull - возможно, то же самое относится и к значениям NSString в CoreData.

Точно так же вы можете иметь пустые элементы в JSON, возвращаемые с сервера, и некоторые парсеры будут выдавать это как объект NSNull. Таким образом, в обоих случаях вы должны быть осторожны при использовании значений, поскольку то, что вы считали объектом NSString или NSNumber, действительно является NSNull.

Одним из решений является определение категории в NSNull, которая просто игнорирует все непонятные сообщения, отправленные объекту, в соответствии с кодом ниже. Тогда ваш код будет работать, потому что NSNull.length вернет 0. Вы можете включить что-то подобное в файл вашего проекта .pch, который включается в каждый отдельный файл вашего проекта.

// NSNull+IgnoreMessages.h
@interface NSNull(IgnoreMessages) 
- (void)forwardInvocation:(NSInvocation *)anInvocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
@end

//NSNull+IgnoreMessages.m
#import "NSNull+IgnoreMessages.h"
@implementation NSNull(IgnoreMessages)
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ( [self respondsToSelector:[anInvocation selector]] )
      [anInvocation invokeWithTarget:self];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *sig=[[NSNull class] instanceMethodSignatureForSelector:aSelector];
        // Just return some meaningless signature
    if(sig==nil)
      sig=[NSMethodSignature signatureWithObjCTypes:"@^v^c"];

    return sig;
}
@end
...