Inicializando variable estática en Objective-C

En una clase de Objective-C, quiero cargar solo una vez el contenido de un archivo de texto en un NSString para que pueda ser utilizado por todas las instancias de esa clase.

En el mundo de Java, aprendí a lo largo de los años que es fácil equivocarse sutilmente en términos de seguridad de subprocesos si no usa un idioma probado. Así que me gustaría asegurarme de que uso el idioma correcto.

¿Me puede mostrar un ejemplo de una clase de Objective-C que hace esto?

Aquí está mi clase vacía con la que estoy empezando...

@interface TestClass : NSObject
- (NSString *)doSomething:(NSUInteger)aParam;
@end

@implementation TestClass {
}

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

    }
    return self;
}

- (NSString *)doSomething:(NSUInteger)aParam {
     // something with shared NSString loaded from text file, 
     //  depending on the value of aParam
     return @""; 
}
@end

preguntado el 28 de agosto de 12 a las 14:08

4 Respuestas

Una forma idiomática de tratar con propiedades estáticas en Objective C es esconderlas detrás de métodos de clase (los que tienen +). Declare su cadena como un static dentro de la implementación de su método de clase, y use dispatch_once para la inicialización:

+ (id)stringFromFile {
    static dispatch_once_t once;
    static NSString *sharedString;
    dispatch_once(&once, ^{
        sharedString = [NSString
            stringWithContentsOfFile:@"MyFile"
            encoding:... // ...supply proper parameters here...
            error:...];
    });
    return sharedString;
}

Esta forma de configurar objetos estáticos es segura para subprocesos. los sharedString se inicializará una vez, incluso si el método se llama simultáneamente desde varios subprocesos.

Ahora puede acceder a su cadena desde cualquier lugar llamando [MyClass stringFromFile].

Respondido 28 ago 12, 14:08

Este es exactamente el tipo de respuesta informada que estaba buscando. Gracias. - steve mcleod

Cree una variable de instancia para que accedan las instancias de su clase y una variable estática dentro de su inicializador designado. Su inicializador designado debe crear el objeto de cadena una vez (manteniéndolo en la variable estática) y asignarlo a la variable de instancia cada vez. Por ejemplo:

@implementation TestClass {
    NSString *_myString;
}

- (id)init {
    self = [super init];
    if (self == nil) return nil;

    static dispatch_once_t once;
    static NSString *aString = nil;
    dispatch_once(&once, ^{
        aString = ... // However you want to instantiate the string
    });
    _myString = aString;

    return self;
}

Esto le permite acceder a la cadena en sus métodos de instancia como si fuera una variable de instancia normal, a pesar de que la cadena se crea solo una vez y cada instancia apunta al objeto único.

Respondido 28 ago 12, 14:08

¿Es seguro tener el final "_myString = aString;"? fuera del bloque dispatch_once? - steve mcleod

Sí. Sería incorrecto si lo pones dentro del dispatch_once bloque: el objetivo de ese bloque es que solo se ejecuta una vez. Necesita que la asignación se ejecute para cada instancia de su clase; de ​​lo contrario, solo una instancia de su clase tendrá un valor no nulo _myString. aString solo tendrá un valor, y la asignación solo ocurrirá después de que se establezca ese valor. - Jim

- (NSString *)doSomething:(NSUInteger)aParam { 

    static NSString *foo = nil;

    if (!foo) {
        //load foo
    }

    return @"";  
}

Respondido 28 ago 12, 14:08

contestado el 23 de mayo de 17 a las 11:05

¿Pero es lo que estoy describiendo un Singleton? Tendré muchas instancias de mi clase, pero quiero que todas compartan el acceso a un NSString específico, inicializado cuando se crea la primera instancia de la clase. - steve mcleod

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.