domingo, 30 de junho de 2013

Os nulos do Objective-C (NULL x nil x Nil x NSNull)


Uma das coisas que chamam bastante atenção de quem inicia no desenvolvimento de aplicações para iOS e começa a aprender a linguagem Objective-C é o grande número de representações de valores nulos.




Dessa forma, pode-se encontrar os nulos sendo declarados das seguintes formas:
  • NULL
  • nil
  • Nil
  • NSNull
Por baixo dos panos, não tem muita diferença entre os três primeiros; mas, por convenção, existem algumas variações sutis e comportamentos particulares são atribuídos a cada um deles.

Assim, ainda em relação aos três primeiros, todos representam valores nulos, ou "zero pointers". A diferença é que "NULL" representa "0" para ponteiros convencionais do C, "nil" é específico para objetos (ou para o tipo abstrato "id"), e "Nil" para ponteiros de classes.

Exemplos de utilização de "NULL":
int *pointerToInt = NULL;
char *pointerToChar = NULL;
struct TreeNode *rootNode = NULL;

Exemplos de utilização de "nil":
NSString *someString = nil;
id someObject = nil;
if (anotherObject == nil) //do something

Exemplos de utilização de "Nil":
Class someClass = Nil;
someClass = [NSString class];

Uma característica "interessante" do Objective-C é que métodos podem ser invocados a partir de objetos "nil" sem que sejam lançadas exceções do tipo "null pointer". Nesse caso, eles apenas retornarão "0" e a aplicação seguirá no seu fluxo normal.

Com isso, aqueles códigos, tipicamente encontrados no Java, que verificam se o objeto é nulo antes de chamar um método, podem ser simplificados, conforme pode ser exemplificado no exemplo abaixo.

Código Java:
if(value && value.isGood()){
    //do stuff with value.
}

Código Objective-C:
if([value isGood]) {
  //do stuff with value. 
}

Dessa forma, se o valor for nulo, o método vai retornar zero e o código dentro do if não será executado.

Obs.: Bom, isso pode ser visto como um benefício, ou como um ponto de risco, já que objetos que representam números (como o NSNumber) também podem ter o valor igual a "0" e, dependendo da situação, não vai ser possível diferenciar se o valor era mesmo nulo, ou se foi atribuído como "0".


Por fim, o "NSNull" é um objeto utilizado para representar o "nil" em situações nas quais não é possível utilizar "nil". Por exemplo, em coleções como o NSSet, o NSArray ou o NSDictionary, não se pode armazenar "nil", então se utilizaria um "NSNull".

Para utilizá-lo, deve-se invocar o método DE classe "null" DA classe "NSNull", conforme o exemplo abaixo. Esse método irá retornar uma instância singleton da classe NSNull".

Exemplo de utilização de "NSNull":
NSNull *nullValue = [NSNull null];
NSArray *arrayWithNull = @[nullValue];
NSLog(@"arrayWithNull: %@", arrayWithNull);
//output: "arrayWithNull: (<null>)"

NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:[NSNull null] forKey:@"someKey"];

Nenhum comentário: