2012-01-09 44 views
11

Hola tenía una implementación de versiones anteriores de iOS para un producto único de la siguiente manera:Singleton en iOS 5?

archivo .h

@interface CartSingleton : NSObject 
{ 

} 
+(CartSingleton *) getSingleton; 

archivo .m

@implementation CartSingleton 

static CartSingleton *sharedSingleton = nil; 

+(CartSingleton *) getSingleton 
{ 
    if (sharedSingleton !=nil) 
     { 
     NSLog(@"Cart has already been created....."); 
     return sharedSingleton; 
     } 
    @synchronized(self) 
    { 
    if (sharedSingleton == nil) 
     { 
     sharedSingleton = [[self alloc]init]; 
     NSLog(@"Created a new Cart"); 
     } 
    } 
    return sharedSingleton; 
} 
//============================================================================== 
+(id)alloc 
{ 
    @synchronized([CartSingleton class]) 
    { 
    NSLog(@"inside alloc"); 
    NSAssert(sharedSingleton == nil, @"Attempted to allocate a second instance of a singleton."); 
    sharedSingleton = [super alloc]; 
    return sharedSingleton; 
    } 

    return nil; 
} 

//============================================================================== 
-(id)init 
{ 
    self = [super init]; 
} 

Sin embargo en la web veo que la gente han puesto en práctica el patrón de diseño de Singleton que utiliza este código:

+ (id)sharedInstance 
{ 
    static dispatch_once_t pred = 0; 
    __strong static id _sharedObject = nil; 
    dispatch_once(&pred, ^{ 
    _sharedObject = [[self alloc] init]; // or some other init method 
    }); 
    return _sharedObject; 
} 

Podría alguien que es la experiencia por favor guíame. Soy un novato y estoy completamente confundido entre la antigua implementación de iOS de Singleton y la nueva y ¿cuál es la correcta?

Muchas gracias

+0

Ver http://stackoverflow.com/questions/5720029/create-singleton-using-gcds-dispatch-once-in-objective-c de el más moderno, más simple pero aún seguro para hilos. Los bloques –

Respuesta

19

En sentido estricto, debe utilizar:

+ (MySingleton*) instance { 
    static dispatch_once_t _singletonPredicate; 
    static MySingleton *_singleton = nil; 

    dispatch_once(&_singletonPredicate, ^{ 
     _singleton = [[super allocWithZone:nil] init]; 
    }); 

    return _singleton; 
} 

+ (id) allocWithZone:(NSZone *)zone { 
     return [self instance]; 
} 

Ahora se garantiza que no se puede llamar a alloc/init y crear otra instancia.

Explicación: El método de instancia está en el nivel de clase y es su método de acceso principal para obtener una referencia al singleton. El método simplemente usa la cola incorporada dispatch_once() que solo ejecutará un bloque una vez. ¿Cómo garantiza el tiempo de ejecución que el bloque solo se ejecute una vez? Usando el predicado que suministra (del tipo dispatch_once_t). Esta llamada de bajo nivel garantizará que, incluso si hay múltiples hilos tratando de llamarlo, solo uno tiene éxito, los demás esperan hasta que el primero finalice y luego regresa.

La razón por la que anulamos allocWithZone es porque alloc llama a allocWithZone pasando nil como la zona (para la zona predeterminada). Para evitar que el código fraudulento asigne e inicie otra instancia, anulamos allocWithZone para que la instancia pasada sea el singleton ya inicializado. Esto evita que uno cree una segunda instancia.

+1

¿Alguien puede explicar este código con un poco más de detalle para mejorar la respuesta? – djskinner

+0

Espero que la explicación ayude. De lo contrario, haga una pregunta específica para aclaración. –

+0

Excelente, gracias. – djskinner

9

El fragmento dispatch_once es funcionalmente idéntico a otro. Puede leer sobre esto al http://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man3/dispatch_once.3.html.

Esto es lo que yo uso para embarazos únicos:

+ (MySingleton*) getOne { 
    static MySingleton* _one = nil; 

    @synchronized(self) { 
     if(_one == nil) { 
      _one = [[ MySingleton alloc ] init ]; 
     } 
    } 

    return _one; 
} 

NOTA: En la mayoría de los casos, ni siquiera necesito utilizar @synchronized (pero es seguro de esta manera).

+1

también funcionan en iOS 4. –

+0

+ Peter DeWeese: tiene razón. mi error. –

+0

Si no usa @syncrhonized en otro lugar, esto genera una gran cantidad de sobrecarga para manejar excepciones de ObjectiveC, por lo que si no las está utilizando, debe usar la respuesta seleccionada y la versión de bloque. –

0

Un singleton es un tipo especial de clase donde solo existe una instancia de la clase para el proceso actual. (En el caso de una aplicación de iPhone, la única instancia se comparte en toda la aplicación). Algunos ejemplos en UIKit son [UIApplication sharedApplication] (que devuelve la única instancia de la aplicación en sí), y [NSFileManager defaultManager] (que devuelve el instancia del administrador de archivos). Singletons puede ser una manera fácil de compartir datos y métodos comunes en toda su aplicación.

En lugar de crear instancias de la clase singleton usando alloc/init, llamará a un método de clase que devolverá el objeto singleton. Puede asignar un nombre al método de clase, pero la práctica común es llamarlo sharedName o defaultName.

Gracias por confirmar un vínculo con mejor respuesta : http://www.idev101.com/code/Objective-C/singletons.html