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.

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 ++

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.


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.


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.


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).


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.


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".


0

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


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.