web-dev-qa-db-fra.com

Remplacez @property setter et infinite loop

Il y a la classe A avec:

@interface ClassA : NSObject {
}
@property (nonatomic, assign) id prop1;
@end

@implementation
@synthesize prop1;
@end

alors j'ai une sous-classe

@interface ClassB : ClassA {
}
@end

@implementation

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

//This is infinite loop
- (void) setProp1:(id)aProp
{
    self.prop1 = aProp;
}
@end

et ceci est une boucle infinie car setProp1 de ClassB appelle [ClassB setProp1: val] depuis ClassB.

J'ai déjà essayé d'appeler [super setProp1] mais cela

Comment écraser @property et assigner une valeur à l'intérieur du setter écrasé? Et supposons que je ne puisse pas modifier ClassA.

38
Marcin

Assignez simplement la variable d'instance directement, sans utiliser la syntaxe à points pour appeler le setter:

- (void) setProp1:(id)aProp
{
    self->prop1 = aProp;
}

Ce genre de question pose cependant la question. Tout ce que fait cet accesseur est exactement ce que le parent aurait fait - alors quel est l'intérêt de remplacer le parent du tout?

58
Sherm Pendley

Avec XCode 4.5+ et LLVM 4.1, il n'est pas nécessaire de @synthesize, vous obtiendrez un _prop1 auquel vous référer.

- (void) setProp1:(id)aProp
{
    _prop1 = aProp;
}

Fonctionnera très bien.

23
bollhav

Vous ne devez pas utiliser "self" à l'intérieur du setter car cela crée l'appel récursif.

En outre, vous devez vérifier que vous n'affectez pas le même objet, conserver le nouvel objet et libérer l'ancien objet avant l'affectation.

Et vous devez redéfinir le nom du setter, comme suggéré ci-dessus:

@synthesize prop1 = prop1_; 

...

- (void) setProp1:(id)aProp
{
    if (prop1_ != aProp) {
        [aProp retain]; 
        [prop1_ release]; 
        prop1_ = aProp;
    }
}
9
Chris Livdahl

Une autre alternative consiste à définir la variable synthétisée sous un autre nom comme ceci:

@synthesize selectedQuestion = _selectedQuestion;

Et puis faites-y référence comme _selectedQuestion. Cela empêche d'écrire accidentellement selectedQuestion lorsque vous vouliez dire self.selectedQuestion.

Cependant, Apple recommande de ne pas utiliser de soulignement. Vous pouvez utiliser un autre nom, mais la méthode de @ Sherm est la meilleure, à mon humble avis.

5
pixelfreak

Tout simplement @synthesize la propriété souhaitée dans votre sous-classe, vous pouvez alors l'utiliser comme nom pour accéder directement à la propriété:

Interface de classe principale:

@interface AClass : NSObject

@property (nonatomic, assign) id<someProtocol> delegate;

@end

Interface de sous-classe:

@interface BCLass : AClass
@end

Mise en œuvre de la sous-classe:

@implementation BCLass

@synthesize delegate = _delegate;

- (void)setDelegate:(id<someProtocol>)d{
    _delegate = d;
}

@end
4
Daniel