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

18

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

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

И получил:

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

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

    
задан kwcto 13.01.2010 в 23:23
источник
  • Является ли NSNull равным нулю? –  Anon. 13.01.2010 в 23:28
  • Нет. NSNull и nil - это не одно и то же. Не за что. –  bbum 13.01.2010 в 23:47

4 ответа

30

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

Кажется, что в вашем примере myString является NSNull , а не nil , поэтому myString != nil истинно.

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

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

    
ответ дан Georg Schölly 13.01.2010 в 23:28
источник
  • Спасибо за подсказку. Im все еще пытается согласовать себя со всеми соглашениями синтаксиса и именования. –  kwcto 13.01.2010 в 23:35
  • Я бы не сказал, что люди «обычно» не сравниваются с нолем. Я видел, как это делалось в обоих направлениях с одинаковой частотой. Аргументом является то, что вы можете прочитать его как «если myString не ноль», а не «if not myString». –  bobDevil 14.01.2010 в 02:23
  • На самом деле вы неверны по сравнению с nil via (nil == variable) - это правильный способ гарантировать, что сообщение не отправляется никому. –  Matt Hudson 27.10.2011 в 22:54
  • @Inturbidus: Я не уверен, что понял, что вы имели в виду. Если вы считаете, что нужно использовать if (nil == myString), а не if (! MyString), вы ошибаетесь. nil определяется как 0, и поэтому два сравнения точно совпадают. –  Georg Schölly 28.10.2011 в 09:47
  • Технически вы могли бы просто сделать if (myString.length) {...} и оставить это на этом, потому что если myString - это нулевой объект, и вы отправляете ему сообщение длины, вы все равно получите нуль. –  Matt Mc 15.10.2012 в 04:03
Показать остальные комментарии
10

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

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

    
ответ дан Stephen Canon 13.01.2010 в 23:28
источник
  • NString * str = выражениеThatReturnsStrOrNil () || @ ""; не работает. Это оценка короткого замыкания не работает. –  Pedro Morte Rolo 12.09.2012 в 13:51
  • @PedroMorteRolo: Конечно, он работает. Какой результат вы ожидаете? (Имейте в виду, что результат оператора || равен либо 1, либо 0, нигде больше). –  Stephen Canon 12.09.2012 в 14:02
  • Вы правы. Я впал в иллюзию, что C имеет ту же семантику, что и Руби. –  Pedro Morte Rolo 13.09.2012 в 11:03
3

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

ответ дан D.C. 13.01.2010 в 23:28
источник
0

Если у вас есть 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
    
ответ дан Kendall Helmstetter Gelner 14.01.2010 в 02:01
источник
  • Это просто ждет неудачи. Важно знать, когда вы имеете дело с NSNull вместо nil, ваш код делает менее вероятным. В примере вопроса есть сообщение об ошибке, содержащее NSNull, вы бы не увидели это с вашим кодом, и если (myString) все равно будет оценивать значение true. –  Georg Schölly 14.01.2010 в 12:09
  • Так скажите мне, как он может потерпеть неудачу, если вы можете отправить ему какое-либо сообщение, точно так же, как и ноль ... и он по-прежнему будет обращаться к любому сообщению, которое действительно понимается NSNull (включая все методы NSObject). Теперь это может вызвать ошибки, в том случае, если вы явно проверяете эквивалентность на nil, что не будет правдой. Но в большинстве кодировок именно потому, что nil может быть отправлено любое сообщение, я просто тестирую что-то вроде (myString.length> 0), который отлично работает здесь. В самом деле, этот код будет ПРЕДОТВРАТИТЬ возможные сбои в вашем коде, когда NSNull проскальзывает там, где вы этого не ожидали, поэтому на балансе это коэффициент усиления стабильности. –  Kendall Helmstetter Gelner 14.01.2010 в 16:41
  • Кроме того, где говорится об ошибке? Это даже не имеет никакого смысла, почему все, что хочет отправить сообщение об ошибке, отправляет NSNull вместо NSString? На практике я только когда-либо видел NSNull, выходящий из CoreData и некоторых JSON Parsers, таким образом, что этот тест ничего не делает, кроме как предотвратить неочевидные ошибки времени выполнения. Вы все еще можете проверить NSNull, где это важно. –  Kendall Helmstetter Gelner 14.01.2010 в 16:45
  • В вопросе упоминается сообщение об ошибке: - [NSNull length]: непризнанный селектор, отправленный в экземпляр. Я думаю, что очень опасно говорить, что ваша техника предотвращает аварии. Эти сбои будут существовать только потому, что программист не видел, что NSNull возвращается. Это прекрасный пример маскировки ошибок. И в этом случае это может привести к потере данных, если какая-то логика что-то делает с NSNull. –  Georg Schölly 14.01.2010 в 22:59
  • почему не просто NSMethodSignature * sig = [self methodSignatureForSelector: aSelector]; –  user102008 30.07.2011 в 03:21
Показать остальные комментарии