jueves, 14 de marzo de 2013

Optimizaciones del compilador en Objective-C

Cuando se tiene un objeto que es inmutable, por ejemplo un string, es bastante útil contar con optimizaciones del compilador, para que no cree varias instancias idénticas.

Por ejemplo, en Objective-C si hacemos
NSString *a = @"hola";
NSString *b = @"hola";
el compilador se da cuenta que son referencias a la misma instancia, y crea el string @"hola" una sola vez en memoria, por lo que a y b quedan apuntando al mismo objeto.

Lo mismo pasa si se usan objetos de tipo NSNumber. Si tengo por ejemplo
NSNumber *c = @1;
NSNumber *d = @1;
el objeto @1 queda una sola vez en memoria y las variables c y d referencian la misma instancia.

Hasta acá no hay mucha sorpresa. Son objetos inmutables, por lo que no importa mucho que sean la misma instancia... salvo en lo que se puede ahorrar de memoria.

Una curiosidad si se quiere, es que los constructores no siempre pueden ser optimizados. Por ejemplo
NSString *e = [@"h" stringByAppendingString:@"ola"];
crea una nueva instancia del string @"hola".

¿Qué pasa con el método alloc? En principio uno podría pensar que si se usa alloc, debería devolver una nueva instancia. Esto sin embargo no es así para la clase NSNumber. El siguiente código devuelve la misma instancia que la asignada en c y d.
NSNumber *f = [[NSNumber alloc] initWithInt:1];
Raro...

Pero más raro aún, es que el método copy también devuelve la misma instancia.
NSNumber *g = [f copy];
En este caso, ¡c, d, f y g quedan apuntando todas a la misma dirección de memoria!

Esto no es necesariamente un bug o una feature, creo que se puede argumentar a favor y en contra de cada una de las dos opciones. Lo que sí es importante, es conocer como se comportan las herramientas que usamos.

Una última curiosidad,
[NSObject new]
siempre devuelve una nueva instancia, a pesar de que dos NSObject creados de esta forma son indistiguibles...