Variables d’instance d’objective C

OK – donc je suis sûr que ma confusion ici est juste le résultat d’être coincé dans un “état d’esprit Java” et de ne pas comprendre comment Obj C diffère dans ce cas.

En Java, je peux déclarer une variable dans une classe, comme ceci, et chaque instance de cette classe aura sa propre:

MyClass { Ssortingng myVar; MyClass() { // constructor } } 

Dans Obj, CI essayait de faire la même chose en déclarant une variable uniquement dans le fichier .m comme ceci:

 #import "MyClass.h" @implementation MyClass NSSsortingng *testVar; @end 

J’espérais que cette variable avait une scope limitée à cette classe. J’ai donc créé une deuxième classe (identique):

 #import "MySecondClass.h" @implementation MySecondClass NSSsortingng *testVar; @end 

Ce que je vois (et cela m’a déconcerté), c’est que changer la variable dans une classe affecte la valeur vue dans l’autre classe. En fait, si je mets un point d’arrêt et que je “saute à la définition” de la variable,

J’ai créé un projet XCode extrêmement petit qui montre le problème ici

Rien de plus humiliant que de changer de langue 🙂

Merci d’avance.

Change ça:

 @implementation MyClass NSSsortingng *testVar; @end 

à:

 @implementation MyClass { NSSsortingng *testVar; } // methods go here @end 

et vous obtiendrez ce que vous attendiez.

Comme vous l’avez eu, vous créez une variable globale. Les deux variables globales ont été combinées en une seule par l’éditeur de liens, ce qui explique pourquoi les deux ont changé lorsque vous en avez défini une. La variable entre accolades sera une variable d’instance propre (et privée).

Edit: Après avoir été abaissé sans raison apparente, je pensais souligner l’ancienne façon de faire les choses et la nouvelle façon de faire.

L’ancienne façon:

SomeClass.h

 @interface SomeClass : UIViewController  { UITextField *_textField; BOOL _someBool; } @property (nonatomic, assign) BOOL someBool; // a few method declarations @end 

SomeClass.m

 @implementation SomeClass @synthesize someBool = _someBool; // the method implementations @end 

Maintenant, la nouvelle façon améliorée avec le compilateur Objective-C moderne:

SomeClass.h

 @interface SomeClass : UIViewController @property (nonatomic, assign) BOOL someBool; // a few method declarations @end 

SomeClass.m

 @interface SomeClass ()  @end @implementation SomeClass { UITextField *_textField; } // the method implementations @end 

La nouvelle manière présente plusieurs avantages. Le principal avantage est qu’aucun des détails spécifiques à l’implémentation de la classe n’apparaît dans le fichier .h. Un client n’a pas besoin de savoir quels delegates l’implémentation a besoin. Le client n’a pas besoin de savoir quels ivars j’utilise. Maintenant, si l’implémentation nécessite un nouvel ivar ou si elle doit utiliser un nouveau protocole, le fichier .h ne change pas. Cela signifie que moins de code est recompilé. C’est plus propre et beaucoup plus efficace. Cela facilite également l’édition. Lorsque je modifie le fichier .m et me rend compte que j’ai besoin d’un nouvel ivar, apportez la modification dans le même fichier .m que je suis déjà en train d’éditer. Pas besoin de changer de va-et-vient.

Notez également que l’implémentation n’a plus besoin d’ivar ou de @synthesize pour la propriété.

En java

 MyClass { Ssortingng myVar; MyClass() { // constructor } } 

En Objective-c

 MyClass.h @interface MyClass : NSObject{ NSSsortingng* str; // Declaration } @end MyClass.m @implementation MyClass -(void)initializieTheSsortingng { //Defination } @end 

Ce que vous voulez probablement (sauf si vous utilisez un système d’exploitation et un compilateur très anciens) est d’utiliser simplement la syntaxe de propriété. C’est à dire:

 @interface MyClass : NSObject // method declarations here ... @property (copy) NSSsortingng* myVar; // ... or here. @end 

Cela fera ce que vous aviez l’intention de faire. Cela synthétisera implicitement une variable d’instance et une paire getter / setter pour cette variable. Si vous vouliez manuellement créer la variable d’instance (vous n’en avez généralement pas besoin sauf si vous avez besoin de votre code pour travailler sur d’anciennes versions de MacOS), voici ce que le code ci-dessus fait pour créer l’ivar:

 @interface MyClass : NSObject { NSSsortingng* _myVar; } // method declarations here. @end 

Notez les accolades, qui indiquent au compilateur qu’il ne s’agit pas d’une variable globale entre les méthodes, mais d’une variable d’instance appartenant à cet object.

Si vous ne créez la propriété que pour un usage interne et que vous ne voulez pas que les clients de votre classe le gâchent, vous pouvez le cacher un peu dans tout sauf les plus anciens compilateurs ObjC en utilisant une extension de classe qui “continue” la classe. déclaration de l’en-tête, mais peut être placé séparément (donc généralement dans votre fichier d’implémentation). Une extension de classe ressemble à une catégorie sans nom:

 @interface MyClass () @property (copy) NSSsortingng* myVar; @end 

Et vous pouvez y mettre votre déclaration de propriété, ou même des déclarations ivar (encore une fois entre accolades). Vous pouvez même déclarer la même propriété que readonly dans l’interface de classe, puis la déclarer à readwrite comme étant readwrite dans l’extension, afin que les clients ne puissent la lire que si votre code le modifie.

Notez que si vous n’utilisiez pas ARC (c’est-à-dire que vous avez désactivé la valeur par défaut du comptage automatique des références), vous devez définir toutes vos propriétés sur nil dans votre méthode dealloc (sauf si elles sont définies sur weak ou assign bien sûr).

NB – Tous les éléments ci-dessus sont des sections @interface . Votre code actuel ira dans des sections distinctes de @implementation . C’est ainsi que vous pouvez avoir des fichiers d’en-tête ( .h ) que vous pouvez .m aux clients de votre classe, contenant uniquement les parties que vous souhaitez utiliser, et masquer les détails d’implémentation dans le fichier d’implémentation. devoir s’inquiéter de quelqu’un pourrait les avoir accidentellement utilisés et vous casser d’autres codes.

PS – Notez que NSSsortingngs et les autres objects dont vous voulez la version immuable, mais qui existent également dans une version mutable ( NSMutableSsortingng ) doivent toujours être des propriétés de copy , car cela transformera NSMutableSsortingng en NSSsortingng afin que personne ne puisse changez la chaîne mutable sous vous. Pour tous les autres types d’objects, vous utilisez généralement strong (ou retain si pas ARC). Pour le propriétaire de votre classe (par exemple, son délégué), vous utilisez généralement weak (ou assign si pas ARC).

Dans objective-c, vous définissez la variable comme privée en faisant comme ça

 MyClass.h @interface MyClass : NSObject{ NSSsortingng* _myTestVar; // Declaration } @end 

et s’y référer dans la classe d’implémentation en faisant comme si MyClass.m

 #import "MyClass.h"; @implementation MyClass -(void)initializieTheSsortingng { _myTestVar= @"foo"; //Initialization } @end