Qual é a maneira correta de verificar se há uma sequência nula no Objective-C?

184

Eu estava usando isso no meu aplicativo para iPhone

if (title == nil) {
    // do something
}

mas gera alguma exceção, e o console mostra que o título é "(nulo)".

Então, eu estou usando isso agora:

if (title == nil || [title isKindOfClass:[NSNull class]]) {
    //do something
}

Qual é a diferença e qual é a melhor maneira de determinar se uma string é nula?

Teo Choong Ping
fonte
Solução: jayprakashdubey.blogspot.in/2014/09/…
Jayprakash Dubey

Respostas:

395

Como outros já apontaram, existem muitos tipos de "null" em Cocoa / Objective C. Mas outra coisa a ser observada é que [title isKindOfClass: [NSNull class]] é sem sentido complexo, pois [NSNull null] está documentado como um singleton para que você possa apenas verificar a igualdade do ponteiro. Consulte os tópicos para cacau: usando nulo .

Portanto, um bom teste pode ser:

if (title == (id)[NSNull null] || title.length == 0 ) title = @"Something";

Observe como você pode usar o fato de que, mesmo que o título seja nulo, title.length retornará 0 / nil / false, ou seja, 0 neste caso, para que você não precise caso especial. Isso é algo com o qual as pessoas que são novas no Objective C têm problemas para se acostumar, especialmente em outros idiomas em que as mensagens / métodos chamam para nada travar.

Peter N Lewis
fonte
Obrigado! No entanto, eu fiz essa pergunta em primeiro lugar porque estava recebendo exceção porque o "título" nulo.
Teo Choong Ping
1
Que tipo de título deve ser? Se for um NSString, por exemplo, recebo o seguinte aviso: comparação de tipos diferentes de Objective-C 'struct NSNull *' e 'struct NSString *' não possui conversão. Existe alguma maneira de remover isso (não sei se as coisas mudaram desde esta pergunta foi feita)?
thebossman
1
Serve-me bem para postar código sem compilá-lo ;-). title é presumivelmente um NSString, mas, independentemente do tipo de título, basta converter nulo no tipo de ID genérico: (id) [NSNull null].
Peter N Lewis
1
@JLT nil e [NSNull null] nunca mais serão os mesmos. [NSNull null] é um objeto singleton que pode ser usado como substituto de zero quando nulo não pode ser usado (por exemplo, em um valor NSArray ou NSDictionary). Portanto, um caso de uso pode ser onde você possui um NSArray de cadeias opcionais, algumas das quais podem ser nulas, e você usa [NSNull null] na matriz para os casos nulos. Na prática, o teste raramente é necessário, somente quando você (ou uma biblioteca que você usa!) Usa ativamente [NSNull null] como um espaço reservado.
Peter N Lewis
1
Vindo aqui de Flutter e procurando o motivo pelo qual Mapo valor de um item - que está nullno Dart - não corresponde ao Objetivo C. nilou NULLno Objetivo C. O motivo era que, na verdade NUNull null, não é NULLnulo. Obrigado @PeterNLewis!
Aleksandar
25

é tão simples quanto

if([object length] >0)
{
  // do something
}

lembre-se de que no objetivo C, se o objeto for nulo, ele retornará 0 como o valor.

Isso fornecerá a você uma cadeia nula e uma cadeia de comprimento 0.

Bluephlame
fonte
49
Isso não funcionará se o objeto for NSNull, ainda será necessário verificar explicitamente isso primeiro.
Jeremy Mack
6
Você também pode fazer uma categoria para NSNull para torná-lo retornar 0 para a mensagem comprimento :)
Mihai Timar
1
Sim, isso falhará se o objeto for NSNull.
Mike Gledhill
Isto irá falhar se objeto é igual a NSNull
joana
1
Além do problema do seletor NSNull não reconhecido, isso não diferencia entre um ponteiro NSString que é nulo ou um NSString que está realmente lá, mas é essencialmente uma string vazia. (Por exemplo, como um literal object = @"";ou object = nil;)
KellyTheDude
6

Consulte os seguintes artigos relacionados neste site:

Acho que seu erro está relacionado a outra coisa, pois você não precisa fazer a verificação extra.

Consulte também esta pergunta relacionada: Verificação adequada da coluna de texto nula sqlite

TimM
fonte
Irritantemente, não tenho "pontos" suficientes para adicionar um segundo hiperlink (mesmo para algo neste site), veja também: - stackoverflow.com/questions/598396/…
TimM 9/09/09
...permita-me. Embora você deve ser capaz de editar suas próprias mensagens de rep 0.
Rog
Obrigado - isso foi muito gentil. Quando escrevi meu post inicial, ele dizia que algo como novos usuários só podem adicionar 1 hiperlink (o que parece um pouco duro - especialmente para links cruzados neste site).
10132 TimM
6

Eu descobri que, para realmente fazer certo, você acaba fazendo algo semelhante a

if ( ( ![myString isEqual:[NSNull null]] ) && ( [myString length] != 0 ) ) {
}

Caso contrário, você terá situações estranhas nas quais o controle ainda ignorará seu cheque. Eu não encontrei um que supere as isEqualverificações de comprimento.

Guardius
fonte
5

O que há com todas essas "funciona para mim respostas"? Estamos todos codificando no mesmo idioma e as regras são

  1. Verifique se a referência não é nula
  2. Verifique e verifique se o comprimento da string não é 0

É isso que funcionará para todos. Se uma determinada solução "apenas funciona para você", é apenas porque o fluxo do aplicativo não permite um cenário em que a referência pode ser nula ou o comprimento da string seja 0. A maneira correta de fazer isso é o método que manipulará o que você quer em todos os casos.

nenchev
fonte
4
Se a referência for nil(note: not "null"), o envio de uma mensagem, como length, produzirá 0 (ou o valor 0 apropriado para o tipo de retorno do método). Essa é a regra da linguagem. Não há necessidade de procurar nilseparadamente nesse caso.
JSCs
Eu disse nulo simplesmente por causa dos hábitos de C ++ e, se seu código está chamando métodos em objetos nulos, é provável que seu código esteja quebrado. Você verá que chamar métodos em NULL / NIL (mesmo conceito) geralmente é uma má ideia em qualquer idioma. Só porque obj-c permite que você faça algo assim não significa que você deve apenas passar objetos nulos e tentar usá-los sem se importar.
nenchev
1
O envio de comprimento para zero produz 0 - mas o envio para NSNull produz uma exceção.
Cddamper
@nenchev Ninguém diz nada sobre apenas passar objetos nulos, mas verificar nulo, chamar um método e usar seu valor de retorno é IMO pior do que usar um recurso de linguagem como ele deve ser usado e verificar a validade do valor de retorno do método posteriormente.
Kevin
@ Kevin Eu não tenho certeza de como é realmente pior, só porque é um recurso de linguagem não significa que é ótimo. Não verificar se seu nulo pode abrir um caminho de código que pode levar a um erro de tempo de execução mais difícil de rastrear. Geralmente é melhor verificar se suas entradas são as esperadas e reagir de acordo, se não estiverem. Pessoalmente, não gosto do "recurso" de não obter exceções em tempo de execução ao tentar enviar uma mensagem para um objeto nulo, pois muitas vezes facilita a perda de alguns erros de tempo de execução.
Nenchev 6/01/16
4

Se você quiser testar todos os objetos nulos / vazios (como cadeias vazias ou matrizes / conjuntos vazios), poderá usar o seguinte:

static inline BOOL IsEmpty(id object) {
    return object == nil
        || ([object respondsToSelector:@selector(length)]
        && [(NSData *) object length] == 0)
        || ([object respondsToSelector:@selector(count)]
        && [(NSArray *) object count] == 0);
}
morrerikh
fonte
2
Na verdade, isso não verifica o objeto == [NSNull null], o que provavelmente faria sentido.
Peter N Lewis
3

Existem duas situações:

É possível que um objeto seja [NSNull null], ou é impossível.
Geralmente, seu aplicativo não deve ser usado [NSNull null];, se você quiser colocar um objeto " nulo " em uma matriz ou usá-lo como um valor de dicionário. E então você deve saber quais matrizes ou dicionários podem conter valores nulos e quais podem não.
Se você acha que uma matriz nunca contém [NSNull null]valores, não verifique. Se houver [NSNull null], você pode obter uma exceção, mas isso é bom: as exceções de Objective-C indicam erros de programação. E você tem um erro de programação que precisa ser corrigido alterando algum código.

Se um objeto puder ser [NSNull null], você verifica isso simplesmente testando
(object == [NSNull null]). Ligar isEqualou verificar a classe do objeto é um absurdo. Existe apenas um [NSNull null]objeto, e o operador C simples e antigo o verifica da maneira mais direta e eficiente.

Se você verificar um NSStringobjeto que não pode ser [NSNull null](porque você sabe que não pode ser [NSNull null]ou porque acabou de verificar se é diferente de [NSNull null], então você precisa se perguntar como deseja tratar uma sequência vazia, ou seja, com comprimento 0. Se você tratá-lo como uma nullstring nil, em seguida, (object.length == 0)test.objeto.length retornará 0 se object == nil, portanto, este teste cobre objetos e cadeias nulos com comprimento 0. Se você tratar uma cadeia de comprimento 0 diferente de uma cadeia nula, verifique se object == nil.

Por fim, se você deseja adicionar uma string a uma matriz ou dicionário, e a string pode ser nula, você pode optar por não adicioná-la, substituí-la por @""ou substituí-la por [NSNull null]. Substituí-lo por @""significa que você perde a capacidade de distinguir entre "sem cadeia" e "cadeia de comprimento 0". Substituí-lo [NSNull null]significa que você precisa escrever um código ao acessar a matriz ou o dicionário que verifica se há [NSNull null]objetos.

gnasher729
fonte
Muito tempo, mas isso é bom. O NSNull deve aparecer apenas em singles! Toda esta questão não faz sentido, diz-me o codificador não estava fazendo algo correto, e muitos mais no futuro também, não leu o manual / boas práticas de código
Stephen J
2

Você apenas verifica se não há

if(data[@"Bonds"]==nil){
  NSLog(@"it is nil");
}

ou

if ([data[@"Bonds"] isKindOfClass:[NSNull class]]) {
    NSLog(@"it is null");
}
Gami Nilesh
fonte
2

Solução MACRO (2020)

Aqui está a macro que eu uso para uma string segura em vez de obter a string " (null) " em um UILabel, por exemplo:

#define SafeString(STRING) ([STRING length] == 0 ? @"" : STRING)

digamos que você tenha uma classe de membro e propriedade de nome e nome seja nulo:

NSLog(@"%@", member.name); // prints (null) on UILabel

com macro:

NSLog(@"%@", SafeString(member.name)); // prints empty string on UILabel

agradável e limpo 😊

Solução de Extensão (2020)

Se você preferir verificar nula e nula e vazia no seu projeto, você pode usar minha linha de extensão abaixo:

NSString + Extension.h

///
/// Checks if giving String is an empty string or a nil object or a Null.
/// @param string string value to check.
///
+ (BOOL)isNullOrEmpty:(NSString*)string;

NSString + Extension.m

+ (BOOL)isNullOrEmpty:(NSString*)string {
    if (string) { // is not Nil
        NSRange range = [string rangeOfString:string];
        BOOL isEmpty = (range.length <= 0 || [string isEqualToString:@" "]);
        BOOL isNull = string == (id)[NSNull null];

        return (isNull || isEmpty);
    }

    return YES;
}

Exemplo de uso

if (![NSString isNullOrEmpty:someTitle]) {
    // You can safely use on a Label or even add in an Array for example. Remember: Arrays don't like the nil values!
}
mgyky
fonte
1
if(textfield.text.length == 0){
   //do your desired work
}
Muhammad Aamir Ali
fonte
1

Tente isso para verificar nulo

 if (text == nil)
Vineesh TP
fonte
1
@interface NSString (StringFunctions)
- (BOOL) hasCharacters;
@end

@implementation NSString (StringFunctions)
- (BOOL) hasCharacters {
    if(self == (id)[NSNull null]) {
        return NO;
    }else {
        if([self length] == 0) {
            return NO;
        }
    }
    return YES;
}
@end

NSString *strOne = nil;
if([strOne hasCharacters]) {
    NSLog(@"%@",strOne);
}else {
    NSLog(@"String is Empty");
}

Isso funcionaria com os seguintes casos, NSString *strOne = @""OU NSString *strOne = @"StackOverflow"OU NSString *strOne = [NSNull null]OU NSString *strOne.

Hemang
fonte
0

Se esse tipo de coisa ainda não existir, você poderá criar uma categoria NSString:

@interface NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty;

@end

@implementation NSString (TrucBiduleChoseAdditions)

- (BOOL)isEmpty {
    return self == nil || [@"" isEqualToString:self];
}

@end
Rémy
fonte
Provavelmente é um exagero e acho que não vai resolver esse problema.
Rog
9
O self == nil é inútil - se o self fosse nulo, o Objetivo C não o chamaria em primeiro lugar. [(NSString *) nil isEmpty] simplesmente retornaria 0 / nil / false sem nunca chamar seu código.
9136 Peter N Lewis
4
Na verdade, além disso, [(NSString *) nil isEmpty] retornará false. Ao escrever esses métodos de Objective C, é melhor defini-los para que 0 / nil / false de nil faça sentido; portanto, escrever o método como hasCharacters seria melhor. Observe que length já funciona para isso, pois você pode usar if (s.length) em qualquer lugar que queira usar if (! S.isEmpty) e s.length retornarão corretamente 0 para o caso s == nil.
Peter N Lewis
Este é um acidente grave. Você implementou "isEmpty" para o NSString, mas se for realmente o NSNull, o isEmpty será enviado para o NSNull e trava porque não responde a essa mensagem!
Daniel.gindi
0

O que funciona para mim é if ( !myobject )

Joseph Bolade Caxton-Idowu
fonte
3
Isso não funciona para objetos nulos, apenas objetos nulos. Por exemplo ... NSArray *testarray = [NSArray arrayWithObjects:[NSNull null],@"", nil]; NSString *string = [testarray objectAtIndex:0]; NSLog(@"null string value: %@",string); if (!string) { NSLog(@"string evaluates to null"); } if (string && (string==(id)[NSNull null])) { NSLog(@"string does not evaluate to null"); }
Rik Smith-Unna
Err .. desculpe sobre a formatação, mas o código irá compilar :)
Rik Smith-Unna
0

A verificação completa de uma cadeia de caracteres para condições nulas pode ser a seguinte: <\ br>

    if (mystring)
     {
       if ([mystring isEqualToString: @ ""])
        {
          mystring = @ "alguma string";
        }
     }    
    outro
     {
        //afirmações
     }
Alen Alexander
fonte
0

Eu só checo string nula com

if ([myString isEqual: [NSNull null]]))

JerryZhou
fonte
0
if ([linkedStr isEqual:(id)[NSNull null]])
                {
                    _linkedinLbl.text=@"No";
                }else{
                    _linkedinLbl.text=@"Yes";
                }
SWAMY CHUNCHU
fonte
1
Embora esse trecho de código possa responder à pergunta, ele não fornece nenhum contexto para explicar como ou por quê. Considere adicionar uma ou duas frases para explicar sua resposta.
brandonscript
0
if ([strpass isEqual:[NSNull null]] || strpass==nil || [strpass isEqualToString:@"<null>"] || [strpass isEqualToString:@"(null)"] || strpass.length==0 || [strpass isEqualToString:@""])
{
    //string is blank  
}
saurabh rathod
fonte
0

Para string:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;

}

Consulte a figura abaixo:

insira a descrição da imagem aqui

AmyNguyen
fonte
0

Para string:

+ (BOOL) checkStringIsNotEmpty:(NSString*)string {
if (string == nil || string.length == 0) return NO;
return YES;}
AmyNguyen
fonte