¿Cómo puedo implementar un singleton Objective-C que sea compatible con ARC?


¿Cómo convertir (o crear) una clase singleton que compila y se comporta correctamente cuando se utiliza el conteo automático de referencias (ARC) en Xcode 4.2?

Author: Brad Larson, 2011-09-27

10 answers

Exactamente de la misma manera que usted (debería) haberlo estado haciendo ya:

+ (instancetype)sharedInstance
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}
 366
Author: Nick Forge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-03 00:28:54

Si desea crear otra instancia como needed.do esto:

+ (MyClass *)sharedInstance
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

Si no, deberías hacer esto:

+ (id)allocWithZone:(NSZone *)zone
{
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [super allocWithZone:zone];
    });
    return sharedInstance;
}
 8
Author: DongXu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-08 09:19:32

Esta es una versión para ARC y no ARC

Cómo usar:

Myingletonclass.h

@interface MySingletonClass : NSObject

+(MySingletonClass *)sharedInstance;

@end

Myingletonclass.m

#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end
 5
Author: Igor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-18 14:23:28

Este es mi patrón bajo ARCO. Satisface el nuevo patrón usando GCD y también satisface el viejo patrón de prevención de instanciación de Apple.

@implementation AAA
+ (id)alloc
{
    return  [self allocWithZone:nil];
}
+ (id)allocWithZone:(NSZone *)zone
{
    [self doesNotRecognizeSelector:_cmd];
    abort();
}
+ (instancetype)theController
{
    static AAA* c1  =   nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        c1  =   [[super allocWithZone:nil] init];

        // For confirm...       
        NSLog(@"%@", NSStringFromClass([c1 class]));    //  Prints AAA
        NSLog(@"%@", @([c1 class] == self));            //  Prints 1

        Class   real_superclass_obj =   class_getSuperclass(self);
        NSLog(@"%@", @(real_superclass_obj == self));   //  Prints 0
    });

    return  c1;
}
@end
 2
Author: Eonil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-17 03:57:29

Lee esta respuesta y luego ve y lee la otra respuesta.

Primero debes saber qué significa un Singleton y cuáles son sus requisitos, si no lo entiendes, entonces no entenderás la solución!en absoluto!

Para crear un Singleton con éxito debe ser capaz de hacer lo siguiente 3:

  • Si hubo una condición de carrera , entonces no debemos permitir que se creen varias instancias de su sharedInstance al mismo tiempo tiempo!
  • Recuerde y mantenga el valor entre múltiples invocaciones.
  • Crealo solo una vez. Controlando el punto de entrada.

dispatch_once_t te ayuda a resolver una condición de carrera al permitir que su bloque sea enviado una sola vez.

Static ayuda a "recordar" su valor a través de cualquier número de invocación. ¿Cómo lo recuerda? No permite que se vuelva a crear ninguna instancia nueva con el nombre exacto de tu sharedInstance. con el que fue creado originalmente.

No usar llamar alloc init (es decir, todavía tenemos alloc init métodos dado que somos una subclase NSObject, aunque NO deberíamos usarlos) en nuestra clase sharedInstance, logramos esto usando +(instancetype)sharedInstance, que está limitado a ser iniciado una vez, independientemente de múltiples intentos de diferentes subprocesos al mismo tiempo y recordar su valor.

Algunos de los Singletons más comunes del sistema que vienen con el cacao en sí son:

  • [UIApplication sharedApplication]
  • [NSUserDefaults standardUserDefaults]
  • [NSFileManager defaultManager]
  • [NSBundle mainBundle]
  • [NSOperations mainQueue]
  • [NSNotificationCenter defaultCenter]

Básicamente cualquier cosa que necesitaría tener un efecto centralizado tendría que seguir algún tipo de patrón de diseño único.

 2
Author: Honey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:43

Alternativamente, Objective-C proporciona el método +(void)initialize para NSObject y todas sus subclases. Siempre se llama antes de cualquier método de la clase.

Establecí un punto de interrupción en uno una vez en iOS 6 y dispatch_once apareció en los marcos de la pila.

 1
Author: Walt Sellers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-20 19:28:47

Clase Singleton : Nadie puede crear más de un objeto de clase en cualquier caso o a través de cualquier forma.

+ (instancetype)sharedInstance
{
    static ClassName *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[ClassName alloc] init];
        // Perform other initialisation...
    });
    return sharedInstance;
}
//    You need need to override init method as well, because developer can call [[MyClass alloc]init] method also. that time also we have to return sharedInstance only. 

-(MyClass)init
{
   return [ClassName sharedInstance];
}
 0
Author: Yogi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-29 02:31:57

Hay dos problemas con la respuesta aceptada, que pueden o no ser relevantes para su propósito.

  1. Si desde el método init, de alguna manera se llama de nuevo al método sharedInstance (por ejemplo, porque se construyen otros objetos desde allí que usan el singleton), causará un desbordamiento de pila.
  2. Para las jerarquías de clase solo hay un singleton (a saber: la primera clase en la jerarquía en la que se llamó al método sharedInstance), en lugar de un singleton por concreto clase en la jerarquía.

El siguiente código se encarga de ambos problemas:

+ (instancetype)sharedInstance {
    static id mutex = nil;
    static NSMutableDictionary *instances = nil;

    //Initialize the mutex and instances dictionary in a thread safe manner
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        mutex = [NSObject new];
        instances = [NSMutableDictionary new];
    });

    id instance = nil;

    //Now synchronize on the mutex
    //Note: do not synchronize on self, since self may differ depending on which class this method is called on
    @synchronized(mutex) {
        id <NSCopying> key = (id <NSCopying>)self;
        instance = instances[key];
        if (instance == nil) {
            //Break allocation and initialization into two statements to prevent a stack overflow, if init somehow calls the sharedInstance method
            id allocatedInstance = [self alloc];

            //Store the instance into the dictionary, one per concrete class (class acts as key for the dictionary)
            //Do this right after allocation to avoid the stackoverflow problem
            if (allocatedInstance != nil) {
                instances[key] = allocatedInstance;
            }
            instance = [allocatedInstance init];

            //Following code may be overly cautious
            if (instance != allocatedInstance) {
                //Somehow the init method did not return the same instance as the alloc method
                if (instance == nil) {
                    //If init returns nil: immediately remove the instance again
                    [instances removeObjectForKey:key];
                } else {
                    //Else: put the instance in the dictionary instead of the allocatedInstance
                    instances[key] = instance;
                }
            }
        }
    }
    return instance;
}
 0
Author: Werner Altewischer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-02 15:08:54
#import <Foundation/Foundation.h>

@interface SingleTon : NSObject

@property (nonatomic,strong) NSString *name;
+(SingleTon *) theSingleTon;

@end

#import "SingleTon.h"
@implementation SingleTon

+(SingleTon *) theSingleTon{
    static SingleTon *theSingleTon = nil;

    if (!theSingleTon) {

        theSingleTon = [[super allocWithZone:nil] init
                     ];
    }
    return theSingleTon;
}

+(id)allocWithZone:(struct _NSZone *)zone{

    return [self theSingleTon];
}

-(id)init{

    self = [super init];
    if (self) {
        // Set Variables
        _name = @"Kiran";
    }

    return self;
}

@end

Hope above code lo ayudará.

 -2
Author: kiran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-06 11:48:38

Si necesita crear singleton en swift,

class var sharedInstance: MyClass {
    struct Singleton {
        static let instance = MyClass()
    }
    return Singleton.instance
}

O

struct Singleton {
    static let sharedInstance = MyClass()
}

class var sharedInstance: MyClass {
    return Singleton.sharedInstance
}

Se puede utilizar de esta manera

let sharedClass = LibraryAPI.sharedInstance
 -2
Author: muhammedkasva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-21 14:57:17