web-dev-qa-db-fra.com

Solution de contournement pour réaliser des propriétés protégées en Objective-C

J'ai essayé de trouver une solution de contournement pour déclarer les propriétés @protected dans Objective-C afin que seules les sous-classes de la hiérarchie puissent y accéder (en lecture seule et non en écriture). J'ai lu qu'il n'y a pas de méthode documentée de le faire. C'est pourquoi j'ai pensé à cette solution de contournement et je voulais demander l'avis de StackOverflow à ce sujet.

Chaque classe personnalisée en haut de la hiérarchie contient trois classes, une implémentation et deux interfaces. Nommez-les:

ClassA.h
ClassA_protected.h
ClassA.m

Alors n'importe quelle sous-classe de cette classeA serait comme d'habitude:

ClassB.h
ClassB.m

J'ai d'abord créé l'interface ClassA.h où je déclare une variable int protégée de sorte que toute sous-classe de ClassA puisse y accéder:

@interface ClassA : NSObject{
    @protected
    int _myProtectedInt;
}
@end

La prochaine étape est la solution de contournement dont je parlais. Cependant, une fois que vous l'avez lu, vous verrez qu'il est assez simple. J'ai déclaré une deuxième interface appelée ClassA_protected.h qui fonctionne réellement comme une extension de ClassA.h et nous permet de baliser la propriété comme suit: readonly:

#import "ClassA.h"
@interface ClassA ()
@property (nonatomic , readonly) int myProtectedInt;
@end

La dernière étape de la préparation de la hiérarchie protégée consiste à déclarer son implémentation dans ClassA.m où nous synthétisons uniquement notre propriété:

#import "ClassA_protected.h"
@implementation ClassA
@synthesize myProtectedInt = _ myProtectedInt;
@end

Ainsi, chaque classe devant constituer une sous-classe de ClassA.h importera plutôt ClassA_protected.h. Ainsi, un enfant comme, par exemple, ClassB.h, serait comme suit:

#import "ClassA_protected.h"
@interface ClassB : ClassA
@end

Et un exemple d'accès à cette propriété à partir de l'implémentation de ClassB.m:

@implementation ClassB
-(void) method {
    //edit protected variable 
    _myProtectedInt= 1;

    //normal access
    self.muProtectedInt;
}
@end
39
Alex Salom

Bien sûr, cela fonctionne bien. Apple utilise la même approche, par exemple dans la classe UIGestureRecognizer. Les sous-classes doivent importer le fichier UIGestureRecognizerSubclass.h supplémentaire et remplacer les méthodes déclarées dans ce fichier.

20
Ole Begemann

Pour des "propriétés" simples, utilisez simplement ivar. C'est aussi bon que les propriétés à toutes fins pratiques.

De plus, la valeur par défaut est déjà protégée.

7
Septiadi Agus

Si vous demandez un avis, c’est le mien: Si l’on décide de muter votre 

_myProtectedInt

il réussira probablement quand même, car c'est certainement possible avec le runtime d'Objective-C. Sauf que, votre solution est tout à fait correcte.

3
Oleg Trakhman

Importez l'en-tête protégé dans l'implémentation uniquement. par exemple.

ClassB.h

#import "ClassA.h"
@interface ClassB : ClassA
@end

ClassB.m

#import "ClassA_protected.h"
@implementation ClassB
@end

Et dans un cadre, l'en-tête protégé doit être marqué projet afin qu'il ne soit pas inclus dans les en-têtes publics du cadre. Apple utilise généralement le suffixe _Internal.h pour ses méthodes protégées.

Pour init ou outrepasser une propriété get paresseuse, vous devez avoir un accès direct à l'ivar @proteced. Toutefois, pour votre utilisation, il est préférable de redéclarer la propriété en tant que readwrite, vous pouvez alors tirer parti de toutes les fonctionnalités du setter, atomicity par exemple. .

0
malhal