Variables de niveau de classe statique Objective-C
143
J'ai un film de classe, dont chacun stocke un identifiant unique. En C #, Java, etc., je peux définir un currentID int statique et chaque fois que je définis l'ID, je peux augmenter le currentID et le changement se produit au niveau de la classe et non au niveau de l'objet. Cela peut-il être fait en Objective-C? J'ai trouvé très difficile de trouver une réponse à cela.
Vous voulez que votre ClassA ait une variable de classe ClassB.
Vous utilisez Objective-C comme langage de programmation.
Objective-C ne prend pas en charge les variables de classe comme le fait C ++.
Une alternative :
Simuler le comportement d'une variable de classe à l'aide des fonctionnalités Objective-C
Déclarez / définissez une variable statique dans le classA.m afin qu'elle ne soit accessible que pour les méthodes classA (et tout ce que vous mettez dans classA.m).
Remplacez la méthode de classe d'initialisation NSObject pour initialiser une seule fois la variable statique avec une instance de ClassB.
Vous vous demanderez pourquoi devrais-je écraser la méthode d'initialisation de NSObject. La documentation Apple sur cette méthode a la réponse: "Le runtime envoie initialize à chaque classe d'un programme exactement une fois juste avant que la classe, ou toute classe qui en hérite, reçoive son premier message depuis le programme. (Ainsi, la méthode ne peut jamais être invoquée si la classe n'est pas utilisée.) ".
N'hésitez pas à utiliser la variable statique dans n'importe quelle méthode de classe / instance ClassA.
Pouvez-vous avoir une variable statique de type ClassA dans classA.m?
goatlinks
6
cela pourrait être une question idiote, mais qu'en est-il de la libération dudit souvenir? n'a pas d'importance car il doit vivre aussi longtemps que l'application est en cours d'exécution?
samiq
1
@samiq, consultez Objective-C: Pourquoi conserver une variable statique? . Le pointeur vers l'objet ne peut pas être supprimé, mais l'objet lui-même le peut. Vous ne voulez probablement pas le publier parce que vous le souhaitez probablement aussi longtemps que l'application est en cours d'exécution, mais vous économiserez de la mémoire si vous le libérez, donc si vous savez que vous n'en avez plus besoin, alors vous devriez Publiez-le.
ma11hew28
5
Si initialize () est garanti pour être appelé une seule fois, pourquoi avez-vous besoin du conditionnel "if (! ClassVariableName)"?
jb
23
@jamie, initializeest appelée une fois pour chaque classe (les superclasses avant les sous-classes), mais si une sous-classe ne remplace pas initialize, la classe parente initializesera à nouveau appelée. Par conséquent, une garde est requise si vous ne voulez pas que ce code s'exécute deux fois. Consultez Initialisation d'un objet de classe dans la documentation Objective-C d'Apple.
big_m
31
Depuis 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. Ils sont déclarés comme: @property (class) NSString * someStringProperty ;. Ils ne sont jamais synthétisés. (23891898)
Voici un article explicatif très intéressant que j'ai utilisé comme référence pour éditer cette ancienne réponse.
Réponse de 2011: (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 {staticNSString*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, lorsque vous souhaitez le paramétrer:
[MyClass testHolder:testVal]
Dans le cas où vous voulez pouvoir définir cette pseudo-statique-var à nil, vous pouvez déclarer testHoldercomme ceci:
+(NSString*)testHolderSet:(BOOL)shouldSet newValue:(NSString*)_test {staticNSString*test;if(shouldSet){if(test != nil)[test release];
test =[_test retain];}return test;}
Cool, mais ce n'est pas vraiment une variable globale car elle n'est pas accessible à partir d'autres .mfichiers, et je pense que c'est bien qu'elle soit "globale" dans le Class.mfichier.
ma11hew28
29
Sur votre fichier .m, vous pouvez déclarer une variable comme statique:
staticClassName*variableName = nil;
Ensuite, vous pouvez l'initialiser sur votre +(void)initializeméthode.
Veuillez noter qu'il s'agit d'une simple variable statique C et qu'elle n'est pas statique dans le sens où Java ou C # le considèrent, mais donnera des résultats similaires.
ou s'il doit changer à un autre moment (par exemple dans votre méthode openConnection), incrémentez-le là. N'oubliez pas que ce n'est pas thread-safe tel quel, vous devrez faire la synchronisation (ou mieux encore, utiliser un ajout atomique) s'il y a des problèmes de thread.
Comme pgb l'a dit, il n'y a pas de "variables de classe", seulement des "variables d'instance". La manière objective-c de faire des variables de classe est une variable globale statique à l'intérieur du 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).
(À proprement parler, pas de réponse à la question, mais selon mon expérience, susceptible d'être utile lors de la recherche de variables de classe)
Une méthode de classe peut souvent jouer plusieurs des rôles qu'une variable de classe ferait dans d'autres langues (par exemple, modification de la configuration pendant les tests):
Maintenant, un objet de classe MyClsappelle Resource:changeSomething:avec la chaîne @"Something general"lors d'un appel à doTheThing:, mais un objet dérivé de MySpecialCaseavec la chaîne @"Something specific".
initialize
est appelée une fois pour chaque classe (les superclasses avant les sous-classes), mais si une sous-classe ne remplace pasinitialize
, la classe parenteinitialize
sera à nouveau appelée. Par conséquent, une garde est requise si vous ne voulez pas que ce code s'exécute deux fois. Consultez Initialisation d'un objet de classe dans la documentation Objective-C d'Apple.Depuis 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.
Voici un exemple
Ensuite, vous pouvez y accéder comme ceci:
Voici un article explicatif très intéressant que j'ai utilisé comme référence pour éditer cette ancienne réponse.
Réponse de 2011: (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:
Donc, si vous avez besoin d'obtenir la valeur, appelez simplement:
Et puis, lorsque vous souhaitez le paramétrer:
Dans le cas où vous voulez pouvoir définir cette pseudo-statique-var à nil, vous pouvez déclarer
testHolder
comme ceci:Et deux méthodes pratiques:
J'espère que ça aide! Bonne chance.
la source
.m
fichiers, et je pense que c'est bien qu'elle soit "globale" dans leClass.m
fichier.Sur votre fichier .m, vous pouvez déclarer une variable comme statique:
Ensuite, vous pouvez l'initialiser sur votre
+(void)initialize
méthode.Veuillez noter qu'il s'agit d'une simple variable statique C et qu'elle n'est pas statique dans le sens où Java ou C # le considèrent, mais donnera des résultats similaires.
la source
Dans votre fichier .m, déclarez une variable globale de fichier:
puis dans votre routine d'initialisation, repérez que:
ou s'il doit changer à un autre moment (par exemple dans votre méthode openConnection), incrémentez-le là. N'oubliez pas que ce n'est pas thread-safe tel quel, vous devrez faire la synchronisation (ou mieux encore, utiliser un ajout atomique) s'il y a des problèmes de thread.
la source
Comme pgb l'a dit, il n'y a pas de "variables de classe", seulement des "variables d'instance". La manière objective-c de faire des variables de classe est une variable globale statique à l'intérieur du 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).
la source
Voici une option:
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.
la source
(À proprement parler, pas de réponse à la question, mais selon mon expérience, susceptible d'être utile lors de la recherche de variables de classe)
Une méthode de classe peut souvent jouer plusieurs des rôles qu'une variable de classe ferait dans d'autres langues (par exemple, modification de la configuration pendant les tests):
Maintenant, un objet de classe
MyCls
appelleResource:changeSomething:
avec la chaîne@"Something general"
lors d'un appel àdoTheThing:
, mais un objet dérivé deMySpecialCase
avec la chaîne@"Something specific"
.la source
Vous pouvez renommer la classe en classA.mm et y ajouter des fonctionnalités C ++.
la source
Une autre possibilité serait d'avoir un petit
NSNumber
singleton de sous-classe.la source