2012-08-14 5 views
5

Soy nuevo en la escritura de singletons y tengo que usar uno para un proyecto de iOS actual. Uno de los requisitos es que se puede matar. Sé que esto va en contra del diseño de un singleton, pero, ¿es esto algo que debería/podría hacerse?Desasignación total de un singleton de Objective-C

+0

Por definición, un singleton nunca se puede asignar de nuevo y, por lo tanto, la noción de desasignación no tiene ningún sentido. Derribar para la terminación? Por supuesto. Pero no puedes confiar en que eso suceda, independientemente. – bbum

+0

@bbum Eso depende de la definición. Para mí, la definición definitiva proviene del libro de GoF icónico: "Asegúrate de que una clase solo tenga una instancia". Eso no excluye la destrucción y la reconstrucción. –

+1

Por definición dentro de Cocoa y el desarrollo de iOS, entonces. – bbum

Respuesta

6

Por supuesto podría hacer, pero si está buscando un objeto que pueda crearse, y luego soltarlo cuando no sea necesario ... eso suena como un objeto normal. :)


En general, los singleton controlan sus propios ciclos de vida. Tendrá una discusión unilateral aquí a menos que diga más sobre los dos requisitos (uno, que use un singleton y dos, que pueda ser lanzado a voluntad), y por qué ambos tienen sentido en su caso.

Puede ser porque el singleton envuelve algún otro recurso que es intrínsecamente único (como un recurso de archivo o una conexión de red). Si esto es cierto, generalmente el singleton es el "administrador" de ese recurso, y expondrías el control de ese recurso a través de la interfaz de singleton.

O puede deberse a que el objeto singleton retiene una tonelada de memoria (un búfer de algún tipo), y desea asegurarse de que se enjuague según sea necesario. Si este es el caso, puede ser más inteligente sobre cada uno de sus métodos creando y liberando memoria según sea necesario, o puede hacer que el singleton escuche las notificaciones del sistema con poca memoria y se comporte de manera adecuada.

Esencialmente, me sería difícil construir un caso en el que realmente tuviera sentido que se lanzara el objeto singleton . Un solo objeto básico toma solo un puñado de bytes en la memoria y no hace daño a nadie dando vueltas.

+0

Tuve que convertir una aplicación existente en una biblioteca estática y tuve que convertir toda la lógica de AppDelegate en Singleton para una mínima refactorización de código. La "aplicación de la biblioteca" debe poder presentarse convirtiéndola en el controlador de la ventana de la ventana, o ser presentada/presionada por otro controlador de vista.En el escenario de rootviewcontroller, el singleton se mantendría fiel al diseño y nunca se mataría, los otros 2 escenarios creo que es por qué el requisito de poder matarlo. – MattDice

+3

@MattDice: Entendido, pero es mejor que diseñe alrededor de esto. Si el "AppDelegate" de la biblioteca en realidad no tiene ningún estado (propiedades), entonces podría convertir todos sus métodos en métodos de clase con una búsqueda/reemplazo mecánico. Si lleva el estado (y por lo tanto se convierte efectivamente en un contenedor para los globales), entonces considere si es necesario destruirlo de todos modos, quizás esté bien dejarlo como lo haría con cualquier singleton. Si debe restablecer el estado, considere agregar algún tipo de método '-reset' que restablezca sus propiedades a un estado predeterminado. –

+1

@MattDice: Y tenga en cuenta que si alguna vez puede tener más de una de estas "aplicaciones de biblioteca" vivas en la plataforma de navegación al mismo tiempo, entonces ni siquiera puede usar un singleton si desea mantener el estado para ellas de forma independiente ; en este caso, realmente necesitarías refactorizar. –

3

Seguro no hay problema. Proporciona un nuevo método de clase: [MyClass killSingleton]; Ese método libera el singleton y establece su referencia interna en nil. La próxima vez que alguien pregunte [MyClass sharedSingleton], sigue los mismos pasos que antes para crearlo.

EDITAR: en realidad, en los viejos tiempos tal rutina podría haber anulado el selector release, y se negó a desaparecer. Entonces, como dice el primer comentario a continuación, este es un objeto con alcance estático: se mantiene activo a través de una variable estática que mantiene un conteo de retención de 1 en el objeto. Sin embargo, agregando un nuevo método de clase para anular ese ivar (bajo ARC), liberándolo, logra el resultado deseado. El control sobre la creación de instancias y la liberación del objeto estático se realiza completamente a través de métodos de clase, por lo que es fácil de mantener y depurar.

+1

Esto ya no es un singleton entonces> borrrden

+1

Su comentario es más apropiado para la pregunta que la respuesta. Solo estoy respondiendo preguntas, no juzgando a las personas sobre el uso de términos técnicos. Estoy seguro de que si estuviéramos discutiendo esto en un bar, con una pinta en la mano, todos llegaríamos a una solución diferente para cualquier problema. –

5

Sé que esto va en contra del diseño de un producto único

También va en contra de la gestión de memoria Patten habitual en Objective-C. Normalmente, un objeto consigue retener otro objeto para evitar su destrucción, y liberarlo para permitir que el objeto sea destruido. Destruir explícitamente un objeto, sin embargo, no es algo que otros objetos puedan hacer.

Considere qué pasaría si el objeto A obtiene la instancia compartida S de una clase singleton S. Si A conserva S1, S1 continuará existiendo aunque algún método de clase libere S y establezca la variable global que apunta a la instancia compartida a nil. Cuando la clase más tarde crea una nueva instancia compartida, S2, habrá dos instancias de S, concretamente S1 y S2. Esto viola la propiedad que define el singleton en primer lugar.

Es posible que pueda evitar este problema anulando -retain y tal vez swizzling -release, pero eso parece una gran complejidad para resolver un problema que no debería existir en primer lugar.

Una posible alternativa es restablecer su objeto compartido en lugar de intentar destruirlo. Puede establecer todos sus atributos en algún estado conocido (posiblemente no válido) si lo desea, y luego tener un método de clase para reinicializar el objeto compartido. Solo tenga en cuenta el efecto de todo eso en cualquier objeto que pueda estar usando el objeto compartido.

5

Casi todos los singleton que he escrito (salvo los controladores totalmente UI centrados) terminan siendo refactorizados para no ser singletons. Cada. Soltero. Uno.

Por lo tanto, he dejado de escribir singletons. Escribo clases que mantienen el estado en instancias, como cualquier clase normal, y lo hago de forma aislada de otras instancias. Si son pesadas las notificaciones, siempre pasan self como el objeto que notifica. Ellos tienen delegados. Mantienen el estado interno. Evitan los globales fuera del estado verdaderamente global.

Y, a menudo, puede haber exactamente una instancia de dicha clase en mi (s) aplicación (es). Esa instancia única actúa como un singleton y, de hecho, podría incluso crear una forma conveniente de obtenerla, probablemente a través del delegado de la aplicación oa través de un método de clase (que incluso podría llamarse sharedInstance).

Dicha clase incluye un código de corte que generalmente se divide en dos partes; código para persistir el estado actual para la restauración posterior y código que libera recursos asociados a la instancia.

Conveniente como un singleton. Listo para multiplicar instancias cuando sea necesario.

1

Es contraria al concepto de Singleton, pero puede ser implementado de la siguiente manera para un proyecto basado ARC

//ARC 
@interface Singleton : NSObject 

+ (Singleton *)sharedInstance; 
+ (void)selfDestruct; 

@end 

@implementation Singleton 

static Singleton *sharedInstance = nil; 

+ (Singleton *)sharedInstance { 
    if (sharedInstance == nil) { 
     sharedInstance = [[Singleton alloc] init]; 
    } 
    return sharedInstance; 
} 

+ (void) selfDestruct { 
    sharedInstance = nil; 
} 

@end 
+1

Esto no funcionará. Si marcó el sharedInstance después de configurarlo a cero, existirá en la memoria. Además, esto no proporciona ninguna ayuda si el sharedManager se retiene en cualquier otro objeto. –

0
//This can be implemented using bool variable. If bool no create new instance. 

@interface Singleton : NSObject 

+ (Singleton *)sharedInstance; 

@end 

@implementation Singleton 

static Singleton *sharedInstance = nil; 

+ (Singleton *)sharedInstance { 

     if (!keepInstance) { 
       sharedInstance = [[Singleton alloc] init]; 
       keepInstance = YES; 
     } 
     return sharedInstance; 
} 

@end 
0

que necesitaba para limpiar el producto único por lo que terminaron haciendo lo siguiente:

- (void)deleteSingleton{ 
@synchronized(self) { 
    if (sharedConfigSingletone != nil) { 
     sharedConfigSingletone = nil; 
    } 
} 
} 

Espero que ayude.