2012-09-27 23 views
8

Tengo 2 clases secundarias que heredan de 'MyClass' y cada clase secundaria debe ser singleton.Creando una clase singleton con dispatch_once para clase hiearchy

He utilizado este modelo para obtener una instancia estática cuando no tengo ninguna otra clase que heredan:

+ (MyClass *)getInstance 
{ 
    static dispatch_once_t once; 
    static MyClass *instance; 

    dispatch_once(&once, ^{ 
     instance = [[MyClass alloc] init]; 
    }); 

    return instance; 
} 

Esto funciona muy bien. Ahora, si agrego dos nuevas clases secundarias, FirstClass y SecondClass, que heredan de MyClass, ¿cómo me aseguro de recuperar la clase ChildClass respectiva?

dispatch_once(&once, ^{ 
    // No longer referencing 'MyClass' and instead the correct instance type 
    instance = [[[self class] alloc] init]; 
}); 

FirstClass *firstClass = [FirstClass getInstance]; // should be of FirstClass type 
SecondClass *secondClass = [SecondClass getInstance]; // should be of SecondClass type 

hacer lo anterior significa que siempre que regrese cualquier clase que crea una instancia primero como mi segundo tipo de clase:

first: <FirstClass: 0x884b720> 
second: <FirstClass: 0x884b720> 
// Note that the address and type as identical for both. 

¿Cuál es la mejor manera de crear los únicos clase hija respectivos sin añadir getInstance método para cada una de las clases de niños?

Respuesta

6

A menos que tenga un buen motivo, generalmente debe evitar la creación de subclases de singletons. Crea una situación muy confusa. Si crea un singleton MyClass, ¿puede crear un singleton FirstClass? Dado que FirstClass siempre debe ser utilizable en cualquier parte MyClass es utilizable (por Liskov), ahora hay tres objetos "únicos" MyClass. Ahora ObjC es muy flexible con singletons, y eso es algo bueno, pero esto todavía es muy extraño.

OK, dicho eso, ¿qué hay de tu problema? Primero la solución, luego la respuesta. La solución es que MyClass probablemente no debería ser un singleton, como se discutió anteriormente. Deshágase de getInstance en la superclase y simplemente defínalo en las subclases.

La respuesta a lo que está sucediendo está en su dispatch_once. Está pasando el mismo token estático once en todos los casos. dispatch_once se ejecutará no más de una vez siempre para un token determinado. La única forma de evitar esto es pasar tokens diferentes para cada clase, y no sé de una manera conveniente de hacerlo sin duplicar el código de dispatch_once en cada archivo. Puede tratar de crear diferentes tokens once para cada subclase, pero es probable que haya más problemas y códigos que simplemente duplicar el método sharedInstance.

Por cierto, no lo llame getInstance. "obtener" tiene un significado especial en ObjC, y no significa eso aquí, por lo que es confuso. Esto generalmente se llama sharedInstance, o mejor sharedSomething donde "algo" es su clase.Si realmente quiere decir que debe haber un MyClass y debe haber un FirstClass y debe haber un SecondClass, puede implementar sharedInstance en los tres.

+0

La razón por la que tengo esta jerarquía es que tengo una cantidad de código común compartido y datos que todas mis clases hijas tienen (fuera de la 'instancia compartida'. Esta es también la razón por la que estoy usando la herencia frente a los protocolos. También quería no repita el mismo código de instanciación para las tres clases derivadas. –

+0

+1 sobre el nombre "get". –

1

sabes que los singleton son gnarly, ¿verdad? muchos singletons son un problema mayor. fin de precaución.


puede usar dispatch_once para crear la base singleton. entonces su base podría contener un mapa (por ejemplo, diccionario {clave: ClassName | value: Instance}) de sus tipos derivados.

que está usando dispatch_once sugiere que esto se utilizará en un contexto multiproceso. en ese caso, necesitaría proteger las interacciones con el diccionario utilizando un mutex.

luego sus mensajes de subclases determinarían en función de la clase de mensajería (self) qué clase buscar (creando esa instancia, si es necesario).

+1

La gente tiene que aprender a usar únicos y luego follar por ellos para saber por qué se quiere decir con que son un 'problema más grande'. – mskw

+0

@mskw no quería golpear la Biblia demasiado fuerte, cuando la mayoría de las personas ha escuchado la primera oración = p pero tiene razón. un problema típico es que la eliminación de un global/singleton afecta a muchas fuentes/implementaciones. cuando muchos interactúan, se convierte en un gran estado global entrelazado que a menudo es imposible de reutilizar de una manera diferente a la intención inicial (IOW, para separar). eso significa que muchas de esas clases y dependencias, no solo los singletons, sino también las implementaciones que los usan, son inutilizables para otros programas, lo cual requiere mucho tiempo y muchas pruebas. – justin

0

uso id en su myClass en firstclass como esto

+(instancetype)sharedInstance 
{ 
    static id sharedInstance; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     sharedInstance = [[[self class] alloc] init]; 
    }); 
    return sharedInstance; 
} 

creo que esto debería trabaja

Cuestiones relacionadas