web-dev-qa-db-fra.com

Variables de niveau de classe statique Objective-C

J'ai un film de classe, chacun d'entre eux stockant un identifiant unique. En C #, Java etc.), je peux définir un ID statique actuel et chaque fois que je le définis, je peux augmenter le ID actuel et la modification se produit au niveau de la classe et non au niveau de l'objet. Peut-on le faire dans Objective-C? J'ai eu beaucoup de difficulté à trouver une réponse à cette question.

141
Michael Allen

Description du problème :

  1. Vous voulez que votre ClassA ait une variable de classe ClassB.
  2. Vous utilisez Objective-C comme langage de programmation.
  3. Objective-C ne prend pas en charge les variables de classe comme le fait C++.

Une alternative :

Simuler un comportement de variable de classe à l'aide des fonctionnalités d'Objective-C

  1. Declare/Define une variable statique dans classA.m afin qu'elle ne soit accessible que pour les méthodes classA (et tout ce que vous mettez dans classA.m).

  2. Remplacez la méthode de classe d'initialisation NSObject pour initialiser une seule fois la variable statique avec une instance de ClassB.

  3. Vous vous demanderez pourquoi je devrais écraser la méthode d'initialisation de NSObject. Apple sur cette méthode a pour réponse: "Le runtime envoie l'initialisation à chaque classe d'un programme exactement une fois juste avant la classe, ou toute classe qui en hérite, reçoit son premier message. depuis le programme. (Ainsi, la méthode ne peut jamais être invoquée si la classe n’est pas utilisée.) ".

  4. N'hésitez pas à utiliser la variable statique dans n'importe quelle méthode de classe/instance de ClassA.

Exemple de code :

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

Références :

  1. Les variables de classe ont été expliquées en comparant les approches Objective-C et C++
157
Albaregar

À partir de Xcode 8, vous pouvez définir les propriétés de classe dans Obj-C. Cela a été ajouté pour interagir avec les propriétés statiques de Swift.

Objective-C prend désormais en charge les propriétés de classe, qui interagissent avec les propriétés de type Swift. Elles sont déclarées sous la forme: @property (class) NSString * someStringProperty ;. Elles ne sont jamais synthétisées. (23891898)

Voici un exemple

@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

Ensuite, vous pouvez y accéder comme ceci:

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

Voici un très intéressant article explicatif J'ai utilisé comme référence pour éditer cette ancienne réponse.


2011 Réponse: (ne l'utilisez pas, c'est terrible)

Si vous ne voulez vraiment pas déclarer une variable globale, il existe une autre option, peut-être pas très orthodoxe :-), mais qui fonctionne ... Vous pouvez déclarer une méthode "get & set" comme celle-ci, avec une variable statique à l'intérieur:

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

Donc, si vous avez besoin d'obtenir la valeur, appelez simplement:

NSString *testVal = [MyClass testHolder:nil]

Et puis, quand vous voulez le définir:

[MyClass testHolder:testVal]

Dans le cas où vous voulez pouvoir définir cette pseudo-static-var à nil, vous pouvez déclarer testHolder comme ceci:

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

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

    return test;
}

Et deux méthodes pratiques:

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

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

J'espère que ça aide! Bonne chance.

30
Gonzalo Larralde

Sur votre fichier .m, vous pouvez déclarer une variable comme statique:

static ClassName *variableName = nil;

Ensuite, vous pouvez l’initialiser sur votre méthode +(void)initialize.

Veuillez noter qu'il s'agit d'une variable statique C simple et qu'elle n'est pas statique au sens Java ou C # l'examine, mais produira des résultats similaires.

29
pgb

Dans votre fichier .m, déclarez une variable globale de fichier:

static int currentID = 1;

puis dans votre routine init, notez que:

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

ou si cela doit changer à un autre moment (par exemple dans votre méthode openConnection), incrémentez-le ensuite. N'oubliez pas qu'il n'est pas thread-safe tel quel, vous devrez faire une synchronisation (ou, mieux encore, utiliser un ajout atomique) s'il peut y avoir un problème de thread.

16
Peter N Lewis

Comme l'a dit pgb, il n'y a pas de "variables de classe", seulement des "variables d'instance". La méthode objective-c des variables de classe est une variable globale statique située dans le fichier .m de la classe. Le "statique" garantit que la variable ne peut pas être utilisée en dehors de ce fichier (c'est-à-dire qu'elle ne peut pas être externe).

11
Tom Dalling

Voici une option:

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

Notez que cette méthode sera la seule méthode pour accéder à id, vous devrez donc la mettre à jour d'une manière ou d'une autre dans ce code.

3
Anonymous

(À proprement parler, il ne s'agit pas d'une réponse à la question mais, d'après mon expérience, il peut être utile de rechercher des variables de classe.)

Une méthode de classe peut souvent jouer de nombreux rôles qu'une variable de classe jouerait dans d'autres langues (par exemple, une configuration modifiée au cours des 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

Maintenant, un objet de classe MyCls appelle Resource:changeSomething: avec la chaîne @"Something general" sur appel de doTheThing:, mais un objet dérivé de MySpecialCase avec la chaîne @"Something specific".

2
Jacob Oscarson

vous pouvez renommer la classe classA.mm et y ajouter des fonctionnalités C++.

0
rd_

Une autre possibilité serait d’avoir un petit singleton NSNumber sous-classe.

0
Rudolf Adamkovič