Variabili a livello di classe statica Objective-C


143

Ho un film di classe, ognuno dei quali contiene un ID univoco. In C #, Java ecc. Posso definire un currentID int statico e ogni volta che imposto l'ID posso aumentare il currentID e la modifica avviene a livello di classe e non a livello di oggetto. Questo può essere fatto in Objective-C? Ho trovato molto difficile trovare una risposta per questo.

Risposte:


158

Descrizione del problema :

  1. Volete che la vostra Classe A abbia una variabile di classe ClassB.
  2. Stai usando Objective-C come linguaggio di programmazione.
  3. Objective-C non supporta le variabili di classe come C ++.

Un'alternativa :

Simula un comportamento variabile di classe usando le funzionalità Objective-C

  1. Dichiara / Definisci una variabile statica all'interno di classA.m in modo che sia accessibile solo per i metodi classA (e tutto ciò che inserisci in classA.m).

  2. Sovrascrivi il metodo di inizializzazione NSObject per inizializzare solo una volta la variabile statica con un'istanza di ClassB.

  3. Ti starai chiedendo, perché dovrei sovrascrivere il metodo di inizializzazione di NSObject. La documentazione di Apple su questo metodo ha la risposta: "Il runtime invia l'inizializzazione a ciascuna classe in un programma esattamente una volta appena prima che la classe, o qualsiasi classe che eredita da essa, riceva il suo primo messaggio dall'interno del programma. (Quindi il metodo non può mai essere invocato se la classe non viene utilizzata.) ".

  4. Sentiti libero di usare la variabile statica all'interno di qualsiasi metodo di classe / istanza di ClassA.

Esempio di codice :

file: 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

Riferimenti :

  1. Le variabili di classe hanno spiegato il confronto tra approcci Objective-C e C ++

3
Puoi avere una variabile statica di tipo ClassA all'interno di classA.m?
Link di capra

6
questa potrebbe essere una domanda sciocca, ma per quanto riguarda il rilascio di detta memoria? non importa perché deve vivere finché l'app è in esecuzione?
samiq,

1
@samiq, controlla Objective-C: Perché conservare una variabile statica? . Il puntatore all'oggetto non può essere eliminato, ma l'oggetto stesso può farlo. Probabilmente non vorrai rilasciarlo perché molto probabilmente lo vuoi in giro fino a quando l'app è in esecuzione, ma risparmierai memoria se la rilasci, quindi se sai di non averne più bisogno, allora dovresti rilascialo.
ma11hew28,

5
Se Initize () è garantito per essere chiamato solo una volta, perché è necessario il condizionale "if (! ClassVariableName)"?
jb

23
@jamie, initializeviene chiamato una volta per ogni classe (superclassi prima delle sottoclassi), ma se una sottoclasse non ha la precedenza initialize, la classe genitore initializeverrà richiamata di nuovo. Quindi, è necessaria una guardia se non si desidera che quel codice venga eseguito due volte. Vedi Inizializzazione di un oggetto classe nei documenti Objective-C di Apple.
big_m,

31

A partire da Xcode 8, puoi definire le proprietà della classe in Obj-C. Questo è stato aggiunto per interagire con le proprietà statiche di Swift.

Objective-C ora supporta le proprietà di classe, che interagiscono con le proprietà del tipo Swift. Sono dichiarati come: @property (class) NSString * someStringProperty ;. Non sono mai sintetizzati. (23891898)

Ecco un esempio

@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

Quindi puoi accedervi in ​​questo modo:

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

Ecco un post esplicativo molto interessante che ho usato come riferimento per modificare questa vecchia risposta.


Risposta 2011: (non usare questo, è terribile)

Se davvero non vuoi dichiarare una variabile globale, c'è un'altra opzione, forse non molto ortodossa :-), ma funziona ... Puoi dichiarare un metodo "get & set" come questo, con una variabile statica all'interno:

+ (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;
}

Quindi, se hai bisogno di ottenere il valore, chiama:

NSString *testVal = [MyClass testHolder:nil]

E poi, quando vuoi impostarlo:

[MyClass testHolder:testVal]

Nel caso in cui tu voglia essere in grado di impostare questo pseudo-static-var su zero, puoi dichiarare testHoldercome questo:

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

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

    return test;
}

E due metodi utili:

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

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

Spero che sia d'aiuto! In bocca al lupo.


Fantastico, ma in realtà non è una variabile globale perché non è possibile accedervi da altri .mfile, e penso che vada bene che sia "globale" all'interno del Class.mfile.
ma11hew28,

29

Sul tuo file .m, puoi dichiarare una variabile come statica:

static ClassName *variableName = nil;

Quindi puoi inizializzarlo sul tuo +(void)initializemetodo.

Si noti che questa è una semplice variabile statica C e non è statica nel senso che Java o C # la considerano, ma produrrà risultati simili.


16

Nel tuo file .m, dichiara una variabile globale di file:

static int currentID = 1;

quindi nella tua routine init, fai riferimento che:

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

o se deve cambiare in un altro momento (ad es. nel metodo openConnection), incrementalo lì. Ricorda che non è thread-safe così com'è, dovrai eseguire la sincronizzazione (o meglio ancora, utilizzare un'aggiunta atomica) se potrebbero esserci problemi di threading.


11

Come diceva pgb, non ci sono "variabili di classe", solo "variabili di istanza". Il modo obiettivo-c di fare variabili di classe è una variabile globale statica all'interno del file .m della classe. "Static" garantisce che la variabile non possa essere utilizzata al di fuori di quel file (ovvero non può essere esterna).


3

Ecco un'opzione:

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

Nota che questo metodo sarà l'unico metodo per accedere a id, quindi dovrai aggiornarlo in qualche modo in questo codice.


2

(A rigor di termini non è una risposta alla domanda, ma nella mia esperienza probabilmente sarà utile quando si cercano variabili di classe)

Un metodo di classe può spesso svolgere molti dei ruoli che una variabile di classe avrebbe in altre lingue (ad esempio, una configurazione modificata durante i test):

@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

Ora, un oggetto di classe MyClschiama Resource:changeSomething:con la stringa @"Something general"su una chiamata a doTheThing:, ma un oggetto derivato dalla MySpecialCasestringa @"Something specific".


0

puoi rinominare la classe come classA.mm e aggiungere funzionalità C ++ in essa.


0

Un'altra possibilità sarebbe quella di avere una piccola NSNumbersottoclasse singleton.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.