¿Cómo convierto (o creo) una clase singleton que compila y se comporta correctamente cuando uso el conteo automático de referencias (ARC) en Xcode 4.2?
¿Cómo convierto (o creo) una clase singleton que compila y se comporta correctamente cuando uso el conteo automático de referencias (ARC) en Xcode 4.2?
Respuestas:
Exactamente de la misma manera que (debería) haberlo hecho 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;
}
static
variables @David declaradas dentro de un método / función son las mismas que una static
variable declarada fuera de un método / función, solo son válidas dentro del alcance de ese método / función. Cada ejecución por separado del +sharedInstance
método (incluso en subprocesos diferentes) "verá" la misma sharedInstance
variable.
si desea crear otra instancia según sea necesario. haga 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;
}
de lo contrario, 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;
}
dispatch_once()
bit significa que no obtendrá instancias adicionales, incluso en el primer ejemplo ...?
[[MyClass alloc] init]
y omitir el sharedInstance
acceso. DongXu, deberías mirar el artículo Singleton de Peter Hosey . Si va a anular allocWithZone:
para evitar que se creen más instancias, también debe anular init
para evitar que la instancia compartida se reinicialice.
allocWithZone:
versión. Gracias.
Esta es una versión para ARC y no ARC
Cómo utilizar:
MySingletonClass.h
@interface MySingletonClass : NSObject
+(MySingletonClass *)sharedInstance;
@end
MySingletonClass.m
#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end
Este es mi patrón bajo ARC. Satisface el nuevo patrón con GCD y también satisface el antiguo patrón de prevención de creación de instancias 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
c1
ser una instancia de AAA
la superclase de '? Es necesario llamar +alloc
a self
, no en super
.
super
no significa el objeto de superclase . No puede obtener un objeto de superclase Simplemente significa enrutar mensajes a la versión de superclase del método. super
todavía señala self
clase. Si desea obtener un objeto de superclase, necesita obtener funciones de reflexión en tiempo de ejecución.
-allocWithZone:
método es solo una cadena simple a la función de asignación de tiempo de ejecución para ofrecer un punto de anulación. Entonces, en última instancia, el self
puntero == objeto de clase actual se pasará al asignador, y finalmente AAA
se asignará la instancia.
super
funciona en los métodos de clase.
Lea esta respuesta y luego vaya y lea la otra respuesta.
Primero debe saber qué significa un Singleton y cuáles son sus requisitos, si no lo comprende, entonces no entenderá la solución, ¡en absoluto!
Para crear un Singleton con éxito, debe poder hacer lo siguiente 3:
dispatch_once_t
te ayuda a resolver una condición de carrera al permitir que su bloqueo se envíe una sola vez.
Static
le ayuda a "recordar" su valor en cualquier cantidad de invocaciones. ¿Cómo se recuerda? No permite que se vuelva a crear ninguna instancia nueva con ese nombre exacto de su SharedInstance, solo funciona con la que se creó originalmente.
No usar llamadas alloc
init
(es decir, todavía tenemos alloc
init
métodos ya que somos una subclase de NSObject, aunque NO deberíamos usarlos) en nuestra clase sharedInstance, lo logramos usando +(instancetype)sharedInstance
, que está limitado a iniciarse solo una vez , independientemente de múltiples intentos de diferentes hilos al mismo tiempo y recuerda su valor.
Algunos de los Singletons del sistema más comunes que vienen con Cocoa son:
[UIApplication sharedApplication]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
[NSBundle mainBundle]
[NSOperations mainQueue]
[NSNotificationCenter defaultCenter]
Básicamente, cualquier cosa que deba tener un efecto centralizado deberá seguir algún tipo de patrón de diseño Singleton.
Alternativamente, Objective-C proporciona el método de inicialización + (vacío) para NSObject y todas sus subclases. Siempre se llama antes que 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.
Singleton Class: nadie puede crear más de un objeto de clase en ningún caso ni de ninguna manera.
+ (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];
}
Hay dos problemas con la respuesta aceptada, que pueden o no ser relevantes para su propósito.
El siguiente código se ocupa de estos dos 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;
}
#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
Espero que el código anterior lo ayude.
si necesitas 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
}
puedes usar de esta manera
let sharedClass = LibraryAPI.sharedInstance