Objective-C Variables de nivel de clase estática

143

Tengo una película de clase, cada una de las cuales almacena una identificación única. En C #, Java, etc., puedo definir un int currentID estático y cada vez que configuro el ID puedo aumentar el currentID y el cambio se produce a nivel de clase, no a nivel de objeto. ¿Se puede hacer esto en Objective-C? Me ha resultado muy difícil encontrar una respuesta para esto.

Coeur
fuente

Respuestas:

158

Descripción del problema :

  1. Desea que su ClassA tenga una variable de clase ClassB.
  2. Estás utilizando Objective-C como lenguaje de programación.
  3. Objective-C no admite variables de clase como lo hace C ++.

Una alternativa :

Simule un comportamiento variable de clase utilizando las características de Objective-C

  1. Declare / defina una variable estática dentro de la clase A.M para que solo sea accesible para los métodos de la clase A (y todo lo que ponga dentro de la clase A.)

  2. Sobrescriba el método de clase de inicialización NSObject para inicializar solo una vez la variable estática con una instancia de ClassB.

  3. Te preguntarás, ¿por qué debería sobrescribir el método de inicialización NSObject? La documentación de Apple sobre este método tiene la respuesta: "El tiempo de ejecución envía la inicialización a cada clase en un programa exactamente una vez justo antes de que la clase, o cualquier clase que herede de ella, reciba su primer mensaje desde el programa. (Por lo tanto, el método nunca se puede invocar si no se usa la clase.) ".

  4. Siéntase libre de usar la variable estática dentro de cualquier método de clase / instancia de ClassA.

Código de muestra :

archivo: classA.m

static ClassB *classVariableName = nil;

@implementation ClassA

...
 
+(void) initialize
{
    if (! classVariableName)
        classVariableName = [[ClassB alloc] init];
}

+(void) classMethodName
{
    [classVariableName doSomething]; 
}

-(void) instanceMethodName
{
    [classVariableName doSomething]; 
}

...

@end

referencias :

  1. Variables de clase explicadas comparando los enfoques Objective-C y C ++
Albaregar
fuente
3
¿Puedes tener una variable estática de Tipo ClassA dentro de classA.m?
Goatlinks
66
Esta podría ser una pregunta tonta, pero ¿qué pasa con la liberación de dicho recuerdo? no importa porque tiene que vivir mientras la aplicación se esté ejecutando?
samiq
1
@samiq, mira Objective-C: ¿Por qué retener una variable estática? . El puntero al objeto no se puede eliminar, pero el objeto en sí sí. Probablemente no desee liberarlo porque lo más probable es que lo desee durante todo el tiempo que la aplicación se esté ejecutando, pero ahorrará memoria si lo libera, por lo que si sabe que ya no lo necesita, entonces debería liberarlo.
ma11hew28
55
Si se garantiza que invocar initialize () solo una vez, ¿por qué necesita el condicional "if (! ClassVariableName)"?
jb
23
@jamie, initializese llama una vez para cada clase (superclases antes de las subclases), pero si una subclase no se anula initialize, initializese llamará nuevamente a la clase principal . Por lo tanto, se requiere una protección si no desea que el código se ejecute dos veces. Consulte Inicializar un objeto de clase en los documentos Objective-C de Apple.
big_m
31

A partir de Xcode 8, puede definir propiedades de clase en Obj-C. Esto se ha agregado para interoperar con las propiedades estáticas de Swift.

Objective-C ahora admite propiedades de clase, que interoperan con las propiedades de tipo Swift. Se declaran como: @property (class) NSString * someStringProperty ;. Nunca se sintetizan. (23891898)

Aquí hay un ejemplo

@interface YourClass : NSObject

@property (class, nonatomic, assign) NSInteger currentId;

@end

@implementation YourClass

static NSInteger _currentId = 0;

+ (NSInteger)currentId {
    return _currentId;
}

+ (void)setCurrentId:(NSInteger)newValue {
    _currentId = newValue;
}

@end

Entonces puedes acceder de esta manera:

YourClass.currentId = 1;
val = YourClass.currentId;

Aquí hay una publicación explicativa muy interesante que utilicé como referencia para editar esta vieja respuesta.


Respuesta 2011: (no uses esto, es terrible)

Si realmente no quiere declarar una variable global, hay otra opción, quizás no muy ortodoxa :-), pero funciona ... Puede declarar un método "get & set" como este, con una variable estática dentro:

+ (NSString*)testHolder:(NSString*)_test {
    static NSString *test;

    if(_test != nil) {
        if(test != nil)
            [test release];
        test = [_test retain];
    }

    // if(test == nil)
    //     test = @"Initialize the var here if you need to";

    return test;
}

Entonces, si necesita obtener el valor, simplemente llame:

NSString *testVal = [MyClass testHolder:nil]

Y luego, cuando quieras configurarlo:

[MyClass testHolder:testVal]

En el caso de que desee poder establecer este pseudo-static-var en nil, puede declarar testHolderasí:

+ (NSString*)testHolderSet:(BOOL)shouldSet newValue:(NSString*)_test {
    static NSString *test;

    if(shouldSet) {
        if(test != nil)
            [test release];
        test = [_test retain];
    }

    return test;
}

Y dos métodos útiles:

+ (NSString*)test {
    return [MyClass testHolderSet:NO newValue:nil];
}

+ (void)setTest:(NSString*)_test {
    [MyClass testHolderSet:YES newValue:_test];
}

¡Espero eso ayude! Buena suerte.

Gonzalo Larralde
fuente
Genial, pero no es realmente una variable global porque no se puede acceder desde otros .marchivos, y creo que está bien que sea "global" dentro del Class.marchivo.
ma11hew28
29

En su archivo .m, puede declarar una variable como estática:

static ClassName *variableName = nil;

Luego puede inicializarlo en su +(void)initializemétodo.

Tenga en cuenta que esta es una variable estática de C simple y no es estática en el sentido de que Java o C # lo consideren, pero producirán resultados similares.

pgb
fuente
16

En su archivo .m, declare una variable global de archivo:

static int currentID = 1;

luego, en su rutina de inicio, haga referencia a que:

- (id) init
{
    self = [super init];
    if (self != nil) {
        _myID = currentID++; // not thread safe
    }
    return self;
}

o si necesita cambiar en otro momento (por ejemplo, en su método openConnection), increméntelo allí. Recuerde que no es seguro para subprocesos como es, deberá hacer una sincronización (o mejor aún, usar un agregado atómico) si puede haber algún problema de subprocesamiento.

Peter N Lewis
fuente
11

Como dijo pgb, no hay "variables de clase", solo "variables de instancia". La forma objetiva-c de hacer variables de clase es una variable global estática dentro del archivo .m de la clase. El "estático" asegura que la variable no se pueda usar fuera de ese archivo (es decir, no puede ser externa).

Tom Dalling
fuente
3

Aquí sería una opción:

+(int)getId{
    static int id;
    //Do anything you need to update the ID here
    return id;
}

Tenga en cuenta que este método será el único método para acceder a la identificación, por lo que deberá actualizarlo de alguna manera en este código.

Anónimo
fuente
2

(Estrictamente hablando, no es una respuesta a la pregunta, pero en mi experiencia probablemente sea útil al buscar variables de clase)

Un método de clase a menudo puede desempeñar muchos de los roles que una variable de clase desempeñaría en otros idiomas (por ejemplo, configuración cambiada durante las pruebas):

@interface MyCls: NSObject
+ (NSString*)theNameThing;
- (void)doTheThing;
@end
@implementation
+ (NSString*)theNameThing { return @"Something general"; }
- (void)doTheThing {
  [SomeResource changeSomething:[self.class theNameThing]];
}
@end

@interface MySpecialCase: MyCls
@end
@implementation
+ (NSString*)theNameThing { return @"Something specific"; }
@end

Ahora, un objeto de clase MyClsllama Resource:changeSomething:con la cadena @"Something general"a una llamada a doTheThing:, pero un objeto derivado de MySpecialCasecon la cadena @"Something specific".

Jacob Oscarson
fuente
0

Puede cambiar el nombre de la clase como classA.mm y agregarle funciones de C ++.

rd_
fuente
0

Otra posibilidad sería tener una pequeña NSNumbersubclase singleton.

Rudolf Adamkovič
fuente