Objective-C-Variablen auf statischer Klassenebene

143

Ich habe eine Klasse Film, in der jeder eine eindeutige ID speichert. In C #, Java usw. kann ich eine statische int currentID definieren und jedes Mal, wenn ich die ID einstelle, kann ich die currentID erhöhen und die Änderung erfolgt auf Klassenebene und nicht auf Objektebene. Kann dies in Objective-C durchgeführt werden? Ich habe es sehr schwer gefunden, eine Antwort darauf zu finden.

Cœur
quelle

Antworten:

158

Problembeschreibung :

  1. Sie möchten, dass Ihre ClassA eine ClassB-Klassenvariable hat.
  2. Sie verwenden Objective-C als Programmiersprache.
  3. Objective-C unterstützt keine Klassenvariablen wie C ++.

Eine Alternative :

Simulieren Sie das Verhalten einer Klassenvariablen mithilfe von Objective-C-Funktionen

  1. Deklarieren / Definieren Sie eine statische Variable innerhalb von classA.m, damit nur die classA-Methoden (und alles, was Sie in classA.m einfügen) darauf zugreifen können.

  2. Überschreiben Sie die NSObject-Initialisierungsklassenmethode, um die statische Variable nur einmal mit einer Instanz von ClassB zu initialisieren.

  3. Sie werden sich fragen, warum ich die NSObject-Initialisierungsmethode überschreiben soll. Die Apple-Dokumentation zu dieser Methode hat die Antwort: "Die Laufzeit sendet Initialisierung an jede Klasse in einem Programm genau einmal, kurz bevor die Klasse oder eine Klasse, die von ihr erbt, ihre erste Nachricht aus dem Programm heraus sendet. (Daher die Methode darf niemals aufgerufen werden, wenn die Klasse nicht verwendet wird.) ".

  4. Sie können die statische Variable auch in jeder ClassA-Klassen- / Instanzmethode verwenden.

Codebeispiel :

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

Referenzen :

  1. Klassenvariablen erklärten den Vergleich von Objective-C- und C ++ - Ansätzen
Albaregar
quelle
3
Können Sie eine statische Variable vom Typ ClassA in classA.m haben?
Ziegenböcke
6
Dies mag eine dumme Frage sein, aber was ist mit der Veröffentlichung dieser Erinnerung? spielt keine Rolle, weil es so lange leben muss, wie die App läuft?
Samiq
1
@samiq, check out Ziel-C: Warum eine statische Variable beibehalten? . Der Zeiger auf das Objekt kann nicht gelöscht werden, das Objekt selbst jedoch. Sie möchten es wahrscheinlich nicht veröffentlichen, weil Sie es höchstwahrscheinlich so lange haben möchten, wie die App ausgeführt wird. Sie sparen jedoch Speicher, wenn Sie es veröffentlichen. Wenn Sie also wissen, dass Sie es nicht mehr benötigen, sollten Sie es tun Lass es los.
ma11hew28
5
Wenn initialize () garantiert nur einmal aufgerufen wird, warum benötigen Sie dann die Bedingung "if (! ClassVariableName)"?
jb
23
@jamie initializewird für jede Klasse einmal aufgerufen (Oberklassen vor Unterklassen), aber wenn eine Unterklasse nicht überschreibt initialize, wird die übergeordnete Klasse initializeerneut aufgerufen. Daher ist ein Schutz erforderlich, wenn dieser Code nicht zweimal ausgeführt werden soll. Siehe Initialisieren eines Klassenobjekts in den Objective-C-Dokumenten von Apple.
big_m
31

Ab Xcode 8 können Sie Klasseneigenschaften in Obj-C definieren. Dies wurde hinzugefügt, um mit den statischen Eigenschaften von Swift zusammenzuarbeiten.

Objective-C unterstützt jetzt Klasseneigenschaften, die mit Swift-Typ-Eigenschaften zusammenarbeiten. Sie werden deklariert als: @property (Klasse) NSString * someStringProperty;. Sie werden niemals synthetisiert. (23891898)

Hier ist ein Beispiel

@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

Dann können Sie folgendermaßen darauf zugreifen:

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

Hier ist ein sehr interessanter erklärender Beitrag, den ich als Referenz verwendet habe, um diese alte Antwort zu bearbeiten.


2011 Antwort: (benutze das nicht, es ist schrecklich)

Wenn Sie wirklich wirklich keine globale Variable deklarieren möchten, gibt es eine andere Option, die vielleicht nicht sehr orthodox ist :-), aber funktioniert ... Sie können eine "get & set" -Methode wie diese mit einer statischen Variablen deklarieren:

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

Wenn Sie den Wert erhalten möchten, rufen Sie einfach an:

NSString *testVal = [MyClass testHolder:nil]

Und dann, wenn Sie es einstellen möchten:

[MyClass testHolder:testVal]

Wenn Sie diese pseudostatische Variable auf null setzen möchten, können Sie Folgendes deklarieren testHolder:

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

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

    return test;
}

Und zwei praktische Methoden:

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

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

Ich hoffe es hilft! Viel Glück.

Gonzalo Larralde
quelle
Cool, aber es ist nicht wirklich eine globale Variable, da von anderen .mDateien aus nicht auf sie zugegriffen werden kann, und ich denke, es ist in Ordnung, wenn sie innerhalb der Class.mDatei "global" ist .
ma11hew28
29

In Ihrer .m-Datei können Sie eine Variable als statisch deklarieren:

static ClassName *variableName = nil;

Dann können Sie es auf Ihrer +(void)initializeMethode initialisieren .

Bitte beachten Sie, dass dies eine einfache statische C-Variable ist und nicht statisch im Sinne von Java oder C # ist, sondern ähnliche Ergebnisse liefert.

pgb
quelle
16

Deklarieren Sie in Ihrer .m-Datei eine globale Dateivariable:

static int currentID = 1;

Beachten Sie dann in Ihrer Init-Routine Folgendes:

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

oder wenn es zu einem anderen Zeitpunkt geändert werden muss (z. B. in Ihrer openConnection-Methode), erhöhen Sie es dort. Denken Sie daran, dass es nicht threadsicher ist. Sie müssen eine Synchronisierung durchführen (oder besser noch ein atomares Add verwenden), wenn Threading-Probleme auftreten können.

Peter N Lewis
quelle
11

Wie pgb sagte, gibt es keine "Klassenvariablen", nur "Instanzvariablen". Die objektive Methode zum Ausführen von Klassenvariablen ist eine statische globale Variable in der .m-Datei der Klasse. Die "statische" stellt sicher, dass die Variable nicht außerhalb dieser Datei verwendet werden kann (dh nicht extern sein kann).

Tom Dalling
quelle
3

Hier wäre eine Option:

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

Beachten Sie, dass diese Methode die einzige Methode ist, um auf die ID zuzugreifen. Sie müssen sie daher in diesem Code irgendwie aktualisieren.

Anonym
quelle
2

(Streng genommen keine Antwort auf die Frage, aber meiner Erfahrung nach wahrscheinlich nützlich bei der Suche nach Klassenvariablen)

Eine Klassenmethode kann oft viele der Rollen spielen, die eine Klassenvariable in anderen Sprachen spielen würde (z. B. geänderte Konfiguration während der Tests):

@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

Nun wird ein Objekt der Klasse MyClsAnrufe Resource:changeSomething:mit der Zeichenfolge @"Something general"auf einen Aufruf doTheThing:, sondern ein Objekt , abgeleitet von MySpecialCasemit der Zeichenfolge @"Something specific".

Jacob Oscarson
quelle
0

Sie können die Klasse in classA.mm umbenennen und C ++ - Funktionen hinzufügen.

rd_
quelle
0

Eine andere Möglichkeit wäre, einen kleinen NSNumberSingleton der Unterklasse zu haben .

Rudolf Adamkovič
quelle