Todo lo que querías saber sobre los literales en Objective C

Autor: | Última modificación: 27 de marzo de 2024 | Tiempo de Lectura: 3 minutos
Temas en este post:

Literales para NSString

Desde hace algún tiempo ya, siempre enseño en mis cursos de programación iPhone el uso de literales para las colecciones. Ahorran muchísimo trabajo y ya era hora que Objective-C se apuntase al siglo XX (aprovechando que algunos ya están en el XXI).

Los literales más conocidos son los de siempre, los de las NSStrings. No hace falta crear un NSString de la siguiente manera:

NSString *saludo = [[NSString alloc] initWithCString:"Hola Mundo" 
                                            encoding: NSUTF8StringEncoding];  // Chúpate esa

(gracias sean dadas al Altísimo), sino que basta con un simple:

NSString *saludo = @"Hola Mundo";

Desgraciadamente, hasta hace bien poco, este era el único tipo que tenía una representación literal, lo que hacía que crear un NSArray o un NSDictionary fuese una prueba de paciencia. Afortunadamente, las últimas versiones del compilador (OJO, esto no es un cambio al lenguaje sino al compilador) aceptan literales para NSArray  y NSDictionary.

Aun tenemos que agachar la cabeza con humildad ante los Javascripteros (sí, hijos míos, los Javascripteros), que tienen literales para los objetos en general, y por lo tanto no necesitan inicializadores como el común de los mortales; pero al menos podemos mirar a la cara a Pythonistas y Rubistas.

Literales para NSArray

// Creamos un NSArray de la forma estándar.
// El nil final indica que hemos terminado de meter objetos
 NSArray *lista = [NSArray arrayWithObjects:
                   @"uno",
                   @"dos",
                   nil]; 

 // Mediante literales
 NSArray *lista = @[@"uno", @"dos"];

Es importante tener en cuenta que la representación literal crea la versión inmutable, es decir, NSArray. Si necesitas la mutable, tendrás que enviar el mensaje mutableCopy.

Literales para NSDictionary

Los diccionarios no iban a ser menos, y también tienen una representación literal que recuerda bastante la de Python:

  // Estilo antiguo
  NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                          @"Inception",@"Zimmer",
                          @"Star Wars", @"Williams",
                          nil];

  // Nuevo               Clave        Valor
  NSDictionary *d = @{ @"Zimmer"   : @"Inception",
                       @"Williams" : @"Star Wars"};

Fijaos que en este caso, en la representación literal es al revés del método tradicional (primero la clave y luego el valor). Aquí también el literal devuelve la versión inmutable, y si queremos la mutable tendremos que enviar un mutableCopy.

Lamentablemente, estas son las únicas colecciones para las cuales hay, de momento, expresiones literales. NSSet, por ejemplo, se quedó con las ganas.

Boxing, o literales para números

Hasta aquí, esto ya debería ser conocido por todos, pero ¿y los números? ¿Tenemos que seguir haciendo esto para meterlos en una colección?

// Empaqueto un escalar dentro de un objeto
// (NSNUmber) para poder meterlo en una colección
[NSNumber numberWithInt:42];

A este empaquetado de un escalar dentro de un objeto, se le llama «boxing». Por suerte, tampoco tenemos que hacer esto, y el compilador lo hará por nosotros con tan solo anteponer el símbolo mágico que abre todas las puertas en Objective-C: @.

Además, podemos poner un sufijo que indique el tipo exacto del número (en caso de que no sea evidente).

  • F indica un float (por defecto supone que un decimal es un double).
  • U indica que se trata de un entero sin signo
  • L indica que es un long
  • LL indica que se trata de un looooong (long long) 😉
NSNumber *pi = @3.1425926;      // a double
NSNumber *shortPi = @3.1416F;   // a float

NSNumber *yes = @YES;           // a BOOL

NSNumber *answer = @42U;        // unsigned integer
NSNumber *longInt = @111112222L;// a long
NSNumber *veryLong = @111111111111LL;   // a long long

Todo esto está muy bien y muy bonito, pero y si el número que quieres empaquetar ¿es el resultado de una expresión aritmética? No temas, joven padawan, pues esto también ha sido tenido en cuenta. Para eso basta con poner la expresión entre paréntesis y precedidos de… ¡@! 😉

// Con los dedos de las manos y los dedos de los pies,
// los XXXX y la XXX, todo suma veintitrés:
NSNumber *total = @(10+10+2+1);

El lado Oscuro: sintaxis de indexado

Los diseñadores de LLVM iban tan bien encaminados, pero tan bien encaminados con los literales, que al final tuvieron que cagarla… No contentos con la dádiva de los literales para Objective-C, dieron un paso más, y cayeron en una charca.

Resulta que ahora también puedes acceder a los elementos de una colección con una sintaxis similar a como accederías a un elemento de un array de C:

// Eramos pocos corchetes y parió la abuela
NSArray *jedis = @[@"Windu", @"Luke", @"Yoda", @"Anakin", @"Obi Wan"];

NSString *viejoVerde = nil;

// En vez de...
viejoVerde = [jedis objectAtIndex:2];

// ahora también así
viejoVerde = jedis[2];

Personalmente, me parece una pésima idea. Saltarse la sintaxis habitual de Objective-C para añadir los literales era aceptable por la enorme economía de texto y comodidad que nos aporta. Sin embargo, meter más corchetes en un leguaje que ya tiene bastantes, y encima con un significado completamente distinto, ya me parece de locos.

Expresiones Literales en Objective C para Colecciones y Escalares

Hemos tardado un poco en ponernos al día, pero al fin podemos crear colecciones como las personas normales.

Posts Relacionados