web-dev-qa-db-fra.com

Comment faire une vraie variable d'instance privée?

Je veux créer une variable d'instance à laquelle on ne peut pas accéder de l'extérieur. Est-ce que quelque chose comme ça est possible dans l'objectif-c? Je me souviens Apple a des variables privées et des trucs comme ça, mais si les gens les connaissent, ils peuvent les utiliser. Apple appelle ça "API privée", mais de toute évidence, d'autres peuvent accéder à ces informations s'ils découvrent ce qui s'y trouve.

Jusqu'à présent, je pensais que quelque chose comme ça crée une variable d'instance privée:

@interface MyClass : NSObject {
    CGFloat weight;
}

Pas de @property, pas de @synthesize, juste la déclaration ci-dessus.

Je sais également Apple ajoute un _inFrontOfTheirPrivateInstanceVariables, mais ils ont dit quelque part qu'ils n'aimaient pas voir les autres faire cela car ils pourraient remplacer les variables d'instance cachées accidentellement lors de cette opération.

Quel est le truc ici?

51
HelloMoon

Vous pouvez utiliser le @private mot clé dans le {} pour rendre privées toutes les déclarations de variables suivantes. La visibilité par défaut est @protected (qui est similaire à protected en Java) et qui fonctionne généralement bien. Vous devez déclarer spécifiquement une variable comme @public pour qu'il soit directement accessible en dehors de la classe.

This Apple documentation a plus de détails sur la portée et la visibilité des variables.

Il existe également une différence entre "API privée" et variables privées. Dans Objective-C, vous ne pouvez pas rendre des méthodes privées - n'importe qui peut appeler n'importe quelle méthode. Il existe plusieurs façons de créer des méthodes "secrètes", mais cela sort quelque peu de la portée de cette question. Voici quelques SO questions connexes:

En ce qui concerne le _ devant les variables, sachez que Apple réserve également ce préfixe aux méthodes "privées". La meilleure façon de vous garantir d’éviter les problèmes est d’utiliser des conventions de dénomination normales pour votre Cependant, à moins que vous ne sous-classiez quelque chose de Cocoa (autre que NSObject), vous pouvez être certain que vous ne rencontrerez pas de problèmes.

60
Quinn Taylor

Avec le nouveau compilateur LLVM disponible dans XCode 4 et versions ultérieures, vous pouvez déclarer @private variables dans les catégories par défaut dans votre fichier d'implémentation (.m):

@interface ClassName()
{
@private
// private variables here
}
@end

@implementation ClassName
// you can use private variables here
@end

Je trouve cela pratique, car je déteste les variables privées de pollution apporter dans mes fichiers d'en-tête.

31
Johannes Rudolph

Vous pouvez définir des méthodes privées en les ayant simplement dans la @implementation, et non dans @interface.

De même, vous pouvez définir des variables d'instance privées à l'intérieur d'un bloc anonyme au début de la @implementation - comme vous le faites pour les ivars publics à l'intérieur de la @interface.

Voir l'exemple suivant.

@interface EXClass : NSObject
{
uint8_t publicInteger;
float publicFloat;
}

-(void)publicMethod;
@end

@implementation EXClass
{
uint8_t privateInteger;
float privatefloat;
}

-(BOOL)privateMethod {
return FALSE;
}

N'oubliez pas que les méthodes objective-C sont envoyées sous forme de messages au moment de l'exécution (plutôt que la liaison de compilation de C++), donc respondsToSelector: retournera toujours true et performSelector: appellera toujours la méthode. Les ivars seraient entièrement privés.

Si vous créez une bibliothèque, cependant, théoriquement, personne ne connaîtra les méthodes que vous n'avez pas déclarées dans les fichiers d'en-tête.

9
stef

Tous les iVars dans Objective-C sont protégés par défaut. Si vous n'écrivez pas les méthodes d'accesseur, les autres classes ne pourront pas voir les variables.

Les deux exceptions sont les catégories et les sous-classes.

3
kubi

J'ai vu l'utilisation suivante dans un exemple d'application (PaintGL) par Apple

Dans un fichier .m

@interface MyClass (private)
  - (void) privateMethod();
  @property(...) myProperty;
@end

Avertissement: l'exemple d'application n'a que des déclarations de méthode, j'ai vu la déclaration de propriété privée dans ce fil SO

2
Ege Akpinar

Les documents Apple pour nommer les variables d'instance ne mettent pas explicitement en garde contre l'utilisation du soulignement dans le nom des variables d'instance comme le font les documents de méthode privée.

Nommer les variables d'instance et les types de données

Je me souviens également d'une conversation entre Wil Shipley et quelques autres développeurs OS X concernant les soulignés. En raison de la façon dont le compilateur Obj-C fonctionne, si Apple devait ajouter une nouvelle variable d'instance à une classe dans leurs cadres, cela obligerait toutes les applications utilisant ces cadres à être recompilées. En ce qui concerne les variables d'instance préexistantes, vous devriez recevoir un avertissement lorsque vous marchez dessus.

2
criscokid

Vous pouvez pas créer une véritable variable d'instance privée. Objective-C est un langage dynamique et il est donc possible d'accéder à n'importe quelle variable (même @private).

Ma meilleure approche:

Utilisez-le dans le bloc d'implémentation de votre fichier .m. Ensuite, il n'est pas visible et bloque KVC, de sorte que KVC ne fonctionnera pas

@implementation ClassName {
    // default to @protected
    // but the subclasses can't see ivars created in the implementation block
    float number;
}

+ (BOOL)accessInstanceVariablesDirectly {
    return NO; // no KVC
}

@end
1
Binarian