web-dev-qa-db-fra.com

Objective-C définit la valeur par défaut d'une propriété

Je fais une application, j'ai une classe avec pas mal de propriétés et je me demandais s'il était possible de leur donner une valeur par défaut. Parce que si je fais une méthode init, c'est beaucoup de travail pour tout taper, il y a une grosse chance de faute de frappe et ce n'est tout simplement pas du bon codage ...

Voici à quoi ressemble ma classe:

// Goalkeeping attributes
@property (nonatomic) int aerialAbility;
@property (nonatomic) int commandOfArea;
@property (nonatomic) int communication;
@property (nonatomic) int eccentricity;
@property (nonatomic) int handling;
@property (nonatomic) int kicking;
@property (nonatomic) int oneOnOnes;
@property (nonatomic) int reflexes;
@property (nonatomic) int rushingOut;
@property (nonatomic) int tendencyToPunch;
@property (nonatomic) int throwing;

// Technical attributes
@property (nonatomic) int corners;
@property (nonatomic) int crossing;
@property (nonatomic) int dribbling;
@property (nonatomic) int finishing;
@property (nonatomic) int firstTouch;
@property (nonatomic) int freeKickTaking;
@property (nonatomic) int heading;
@property (nonatomic) int longShots;
@property (nonatomic) int longThrows;
@property (nonatomic) int marking;
@property (nonatomic) int passing;
@property (nonatomic) int penaltyTaking;
@property (nonatomic) int tackling;
@property (nonatomic) int technique;

// Mental attributes
@property (nonatomic) int aggression;
@property (nonatomic) int anticipation;
@property (nonatomic) int bravery;
@property (nonatomic) int composure;
@property (nonatomic) int concentration;
@property (nonatomic) int creativity;
@property (nonatomic) int decisions;
@property (nonatomic) int determination;
@property (nonatomic) int flair;
@property (nonatomic) int influence;
@property (nonatomic) int offTheBall;
@property (nonatomic) int positioning;
@property (nonatomic) int teamwork;
@property (nonatomic) int workRate;

// Physical attributes
@property (nonatomic) int acceleration;
@property (nonatomic) int agility;
@property (nonatomic) int balance;
@property (nonatomic) int jumping;
@property (nonatomic) int naturalFitness;
@property (nonatomic) int pace;
@property (nonatomic) int stamina;
@property (nonatomic) int strength;

Alors, dans l'implémentation, je fais quelque chose comme:

@synthesize aerialAbility = _aerialAbility;

Et je me demandais s'il serait possible de faire ça:

@interface MyClass : NSObject
@property (nonatomic) int someProperty;

@end

@implementation MyClass
@synthesize someProperty = _someProperty = 10;
@end

Je sais que cela ne fonctionnera pas, et cela ne va pas du tout, mais je me demandais s'il y avait un moyen de faire quelque chose comme ça.

Comme dans Java vous pouvez:

class MyClass
{
private int someProperty = 10;
public int getSomeProperty(){return someProperty;}
public void setSomeProperty(int someProperty){this.someProperty = someProperty;}
}
29
Sander Declerck

Je n'ai jamais vu ce comportement auparavant, mais je suis presque sûr que c'est à cela que sert l'étape init lors de l'allocation d'un objet, c'est-à-dire la définition de variables et l'initialisation de l'objet.

-(id)init {
     if (self = [super init])  {
       self.someProperty = 10;
     }
     return self;
}

Et l'appel comme ça:

MyClass* test = [[MyClass alloc] init];

Notez que vous pouvez avoir plusieurs fonctions init, ce qui vous permet d'avoir plusieurs ensembles différents de valeurs par défaut.

Ce que @synthesize fait, c'est de dire au précompilateur qu'il doit générer le code pour le set/get, pas définir la valeur de la propriété. Le '= "indique simplement au pré-remplisseur que, même si le nom de la variable et la propriété ne sont pas identiques, ils doivent être connectés.

En outre, en tant qu'opinion personnelle (pas du tout liée à la question), cet objet semble beaucoup trop grand et vous pourriez être en mesure de le diviser d'une manière ou d'une autre comme le suggère une autre personne. Peut-être que cette classe pourrait hériter de quelques autres classes pour lui donner les différentes propriétés dont elle a besoin? Comme je l'ai dit, c'est juste une suggestion car je ne sais pas à quoi ressemble votre autre code :)

48
chikuba

Pour un si grand nombre d'attributs comme celui-ci, je serais enclin à stocker les données sous forme de dictionnaire plutôt que de propriétés individuelles, et je stockerais les valeurs par défaut dans une liste de propriétés. NSDictionary les objets peuvent être initialisés facilement avec une liste de propriétés.

Si l'utilisation d'un dictionnaire n'est pas à votre goût, je conserverais toujours les valeurs par défaut dans une liste de propriétés, et dans l'initialiseur désigné, je ferais une boucle sur les éléments de la liste des propriétés et les appliquerai à self en utilisant la clé - codage de valeur. Vous devez noter que cela ne convient qu'aux données approuvées, pas aux données fournies par l'utilisateur, car elles pourraient sinon être détournées pour définir d'autres propriétés que vous n'attendez pas.

9
Jim

Il n'y a pas de méthode Java similaire pour initialiser les ivars de propriétés synthétisées ou dans l'Objectif C. Cependant, comme vos propriétés sont presque identiques, vous voudrez peut-être d'envisager de les faire @dynamic au lieu de les synthétiser.

Bien sûr, vous auriez besoin d'écrire deux méthodes effrayantes ( voici un exemple agréable et propre pour vous), mais en retour, vous obtenez un moyen uniforme de stocker vos propriétés en tant qu'objets dans NSMutableDictionary. Cela ouvre plusieurs alternatives intéressantes non disponibles avec les ivars simples: vous pouvez différer l'initialisation de vos propriétés jusqu'à ce qu'elles soient nécessaires, vous pouvez fournir des valeurs par défaut pour les propriétés non définies , ou vous pouvez initialiser vos propriétés "en gros" en remplissant le dictionnaire avec les valeurs de leurs clés.

4
dasblinkenlight

Oui, vous pouvez remplacer getter au cas où définir la valeur par défaut avant que la propriété ne soit modifiée.

Par exemple, définissez la propriété dans le fichier .h:

@interface MySegmentedControl : UISegmentedControl
@property (assign, nonatomic) CGFloat systemFontOfSize;
@end

et remplacer getter et définir la valeur par défaut sous implémentation dans le fichier .m:

@implementation MySegmentedControl    
-(CGFloat) systemFontOfSize
{
    return _systemFontOfSize ? _systemFontOfSize : 17.0f;
}    
@end
1
Tanya Berezovsky

La suggestion de dictionnaire ci-dessus est bonne. J'ai parfois utilisé des objets de configuration dédiés:

@interface GoalKeepingAttributes
@property (nonatomic) int agression
@property (nonatomic) int ... etc
@end

@implementation GoalKeepingAttributes
@end

etc. Si nécessaire, cette classe peut avoir une méthode init qui définit un ensemble de valeurs et de valeurs par défaut.

Vous pourriez également utiliser une structure de style c, car ce ne sont que des primitives.

Il est vrai que cela ne fait que reporter le problème, en déplaçant l'initialisation d'une classe vers la classe config, mais:

  • il faudrait quand même le faire avec un dictionnaire
  • vous pouvez commenter les paramètres de configuration
  • plus grande victoire: la classe config est fortement typée, ce qui capture les erreurs au moment de la compilation, permet l'achèvement du code xcode

Vous pouvez diviser les configurations en différents types (gardien de but, technique et mental). Encore une fois, cela ne fait que diviser le problème, mais cela peut aider à garder les choses concentrées.

0
J.Z.
- (id)init
{
    self = [super init];
    if (self != nil) {
        [self commonInit];
    }

    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self != nil) {
        [self commonInit];
    }

    return self;
}

-(instancetype)initWithCoder:(NSCoder *)aDecoder { //nib init
    self = [super initWithCoder:aDecoder];
    if (self != nil) {
        [self commonInit];
    }
    return self;
}

Vous pouvez définir la valeur par défaut et faire la logique par défaut dans la fonction commonInit si l'objet est une vue. Si ce n'est pas la vue, vous pouvez le faire dans la fonction init à mon avis.

0
Victor Choy

Une autre possibilité serait de remplacer les getters par défaut pour les propriétés. Dans vos getters, vous pouvez regarder pour voir si les valeurs ont été initialisées et, sinon, retourner votre valeur par défaut. (Cela fonctionnerait pour certains types de propriétés, mais pas pour d'autres, clairement - vous avez besoin que la valeur par défaut soit celle qui indique qu'aucune valeur n'a été définie.)

0
Joe Dzikiewicz