6
votes

Masquer la variable d'instance de fichier d'en-tête dans l'objectif c

J'ai rencontré une bibliothèque écrite dans l'objectif C (je n'ai que le fichier d'en-tête et le binaire .a). Dans le fichier d'en-tête, c'est comme ceci:

@interface MyClass : MySuperClass 
{ 
    //nothing here
}

@property (nonatomic, retain) MyObject anObject;
- (void)someMethod;


0 commentaires

10 Réponses :


1
votes

Non, vous ne pouvez pas. Mais vous pouvez le faire si vous n'utilisez pas @property :

.h xxx

.m Xxx


0 commentaires

14
votes

Pour les applications 64 bits et les applications iPhone (bien que non dans le simulateur), la synthèse de la propriété est également capable de synthétiser le stockage pour une variable d'instance.

I.e. Cela fonctionne: xxx

si vous compilez pour le simulateur de Mac OS X ou iPhone, le compilateur donnera une erreur.


2 commentaires

Vous avez raison! Lorsque je passe du simulateur en périphérique, l'erreur disparaît.


Notez que, au fil du temps, le simulateur a de plus en plus de personnes âgées de plus en plus de l'exécution iOS ... Cela fonctionne dans la dernière version, par exemple.



1
votes

Deux possibilités:

  1. Cela pourrait tirer parti de la capacité moderne d'exécution à synthétiser des variables d'instance, comme suggéré BBum.
  2. La propriété peut ne pas avoir une variable d'instance sous-jacente dans cette classe. Les propriétés n'ont pas nécessairement une mappage unique avec des variables d'instance.

0 commentaires

0
votes

Que diriez-vous d'une astuce macro?

avez testé le code ci-dessous

  • ont testé avec des dylibs - a fonctionné bien
  • ont testé sous-classement - avertissement! va casser, je suis d'accord que cela rend l'astuce non pas utile, mais je pense toujours que cela raconte à quel point OBJC fonctionne ...

    myClass.h xxx

    myclass.m xxx


9 commentaires

Le fichier d'en-tête non traité sera inutilisable sans le fichier de mise en œuvre.


Merci, belle tour. Si vous écrivez un article de blog, veuillez donner le lien ici.


Ont vérifié en appelant nslog (@ "% s:% d", __file__, class_getinstancestifize ([[Classe MyClass])); à la fois dans myClass.m et à l'extérieur ... donne la même valeur alors je pense que c'est assez sûr aussi


Non, il ne peut pas fonctionner dans un projet qui n'a pas le fichier .m. Vous dites que vous avez testé avec juste le .h et une bibliothèque de .a compilée et cela a fonctionné?


Cela fonctionnera si vous avez des sous-classes. Les sous-classes seront très cassées (bien que cela puisse fonctionner avec coïncidence sur 64 bits et iPhone). En tout cas, il semble assez chéri fragile.


@bbum je suis d'accord que le sous-classement peut être un problème. Mais je vais de toute façon, mon sentiment d'intestin est que la partie membre du @interface n'est utilisée que par la partie @Implementatation qui peut être masquée dans un fichier .m, de sorte que les membres pourraient ne pas être nécessaires (sauf si vous n'avez pas besoin de dans une sous-classe).


@Chuck je ferai ce test juste pour vous faire plaisir. Le fichier myClass.m est compilé dans un fichier myClass.o, qui peut facilement être placé dans une bibliothèque. Je suis convaincu que cela fonctionnera car les parties importantes semblent être créées par la partie @Implementatation (qui est compilée voir les membres)


@Chuck j'ai testé la création d'une bibliothèque maintenant et ne fournissant que la bibliothèque et un en-tête. Devinez quoi ... ça a fonctionné bien, même comme un dylib.


@bbum a été testé avec sous-classement maintenant et il se cassera. Intéressant.



13
votes

Vous pouvez utiliser le même idiome utilisé dans les classes de cacao. Si vous souhaitez regarder l'interface de classe Nstring dans Nsstring.h, vous verrez qu'il n'ya aucune variable d'instance déclarée. Aller plus profondément dans le code source de gnustep, vous trouverez le truc.

Considérez le code suivant. P>

MyClass.h H2>
@interface MyClassImpl : MyClass {
   // Your private and hidden instance variables here
}
@end

@implementation MyClass

+ (id) allocWithZone:(NSZone *)zone
{
   return NSAllocateObject([MyClassImpl class], 0, zone);
}

// Your methods here
- (void) doSomething {
  // This method is considered as pure virtual and cannot be invoked
  [self doesNotRecognizeSelector: _cmd];          
}

@end

@implementation MyClassImpl

// Your methods here
- (void) doSomething {
  // A real implementation of doSomething
}

@end


1 commentaires

C'est exactement ce que je cherchais et ça marche très bien. Merci!



0
votes

Ne faites pas cela, mais je pense qu'il convient de noter que l'exécution a la capacité d'ajouter des ivars chaque fois que vous voulez avec classe_addivar


1 commentaires

Vous ne pouvez pas ajouter de variables d'instance une fois qu'une classe est enregistrée. Comme toutes les classes générées par le compilateur sont automatiquement enregistrées, cela ne s'applique qu'aux classes créées en appelant objc_allocateclasspair



0
votes

J'ai pu faire ce qui suit dans ma bibliothèque:

myLib.h: xxx

myLib.m xxx

Le protocole est facultatif bien sûr. Je crois que cela rend également toutes vos variables d'instance privées, bien que je ne suis pas 100% certain. Pour moi, c'est juste une interface avec ma bibliothèque statique, de sorte que cela n'a pas vraiment d'importance.

Quoi qu'il en soit, j'espère que cela vous aidera. À quiconque en lisant cela, faites-le-moi savoir si cela est mauvais en général ou qu'il a des conséquences imprévues. Je suis assez nouveau à Obj-C moi-même pour que je puisse toujours utiliser les conseils de l'expérience.


0 commentaires

-1
votes

Je ne pense pas que le code suivant écrit dans une autre réponse fonctionne comme prévu. Les "Soméclass * Certainsvars" définis dans la classe d'extension ne sont pas une variable d'instance de MyClass. Je pense que c'est une variable globale C. Si vous synthétisez des personnes en quelqueilles, vous obtiendrez une erreur de compilation. Et Self.Somevars ne fonctionnera pas non plus non plus.

myLib.h xxx

myLib.m xxx


0 commentaires

7
votes

Vous pouvez utiliser une extension de classe. Une extension de classe est similaire à celle de la catégorie mais sans aucun nom. Sur la documentation Apple, ils définissent simplement des méthodes privées, mais en fait, vous pouvez également déclarer vos variables internes.

myClass.h h1> xxx pré>

myclass.m h1>
#import "PublicClass.h"
#import "InternalClass.h"

// Private interface
@interface MyClass ( /* class extension */ ) 
{
@private
    // Internal variable only used internally
    NSInteger defaultSize;

    // Internal variable only used internally as private property
    InternalClass *internalVar;  

@private 
    // Internal variable exposed as public property 
    PublicClass *publicVar;

    // Internal variable exposed as public property with an other name
    PublicClass *myFooVar;
}

@property (nonatomic, retain) InternalClass *internalVar;

- (void)privateMethod;

@end

// Full implementation of MyClass
@implementation MyClass

@synthesize internalVar;
@synthesize publicVar;
@synthesize publicVarDiffInternal = myFooVar

- (void)privateMethod 
{
}

- (void)publicMethod 
{
}

- (id)init
{
   if ((self = [super init]))
     {
       defaultSize = 512;
       self.internalVar = nil;
       self.publicVar = nil;
       self.publicVarDiffInternal = nil; // initialize myFooVar
     }

   return self;
}
@end


0 commentaires

2
votes

Selon la documentation que j'ai envisagée, il n'y a pas de problème. Tout ce que vous avez à faire pour masquer les variables d'instance consiste à les déclarer au début de la section @Implementatation, à l'intérieur {...}. Cependant, je suis un nouveau venu relatif à l'objectif C et il y a une chance que j'ai mal compris quelque chose - je soupçonne que la langue a changé. J'ai effectivement essayé ce système, en utilisant Xcode 4.2, du code du bâtiment pour l'iPad, et il semble fonctionner correctement.

Une de mes sources pour cette idée est la documentation du développeur Apple sur http://developer.apple.com/library/ios/#documentation/cocoa/conceptuelle /ObjectIVec/Chapters/ocdefiningClasses.html , qui donne ce modèle: P>

@Implementation className p>

{ p>

// Instance variable declarations.


0 commentaires