Singleton en Objective C y Cocoa
Aunque el Singleton parece que se estuviese convirtiendo en el apestado de moda, como el goto de antaño,
no hay motivos suficientes para mandarlo al “pasillo de la muerte”.
Los principales argumentos contra el uso de un Singleton parecen ser:
- Seguridad en código multihebra: Coño, sólo si lo implementas mal.
- Vulnera el principio de una única responsabilidad por clase: Psé, no soy muy fundamentalista que digamos…
- Rendimiento en código multitarea: Dudo mucho que el entrar y salir de un @synchronized sea tu principal cuello de botella, por mucho que hayas abusado del número de singletons.
Además, en casos en que se necesita representar objetos únicos, ya sea dispositivos físicos o recursos de red, un Singleton es la técnica más adecuada.
Implementación básica de un Singleton en Objective C y Cocoa
Una implementación segura y que no hace uso de variables globales sería:
-
#import “MySingleton.h”
-
@implementation MySingleton
-
+(MySingleton *) sharedInstance{
-
static MySingleton *inst = nil;
-
@synchronized(self){
-
if (!inst) {
-
inst = [[self alloc] init];
-
}
-
}
-
return inst;
-
}
-
@end
Gestión de memoria del Singleton
¿Cuando será liberada la instancia estática? A no ser que algún código erróneo sobre libere dicha instancia, sobrevivirá hasta el fin de la aplicación. Si representa algo que puede ser desconectado (un recurso de red o dispositivo físico), la clase debería de observar la notificación correspondiente. Ver “Cocoa Design Patterns” para más detalles.
Implementación Completa del Singleton
La implementación básica no impide que el código cliente pueda crear otras instancias. Si hace falta llegar a esos extremos, habría que sobrescribir todos los métodos de creación:alloc, copy, new.
Otras implementaciones
En StackOverflow, se citan otras muchas implementaciones. la mayoría son seguras en multitarea y hacen grandes esfuerzos para minimizar el coste de sincronización. Probablemente se trate de optimización prematura, pero hay algunas técnicas interesantes, como la aportada por kendall que usa “method-swizzling“.
Si realmente el código de sincronización es un cuello de botella, una implementación alternativa, rápida y sencilla que usa dispatch_once sería:
-
+(MyClass *)singleton {
-
static dispatch_once_t pred;
-
static MyClass *shared = nil;
-
dispatch_once(&pred, ^{
-
shared = [[MyClass alloc] init];
-
});
-
return shared;
-
}