Override @property setter and infinite loop

28,600

Solution 1

Just assign to the instance variable directly, without using dot syntax to call the setter:

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

That kind of begs the question though. All this accessor does is exactly what the parent would have done - so what's the point of overriding the parent at all?

Solution 2

With XCode 4.5+ and LLVM 4.1 there is no need to @synthesize, you will get a _prop1 to refer to.

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

Will work just fine.

Solution 3

You shouldn't use "self" inside the setter since that creates the recursive call.

Also, you should check to make sure you're not assigning the same object, retain the new object and release the old object before assignment.

And you should redefine the setter name, as suggested above:

@synthesize prop1 = prop1_; 

...

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

Solution 4

Another alternative is to set the synthesized variable to another name like so:

@synthesize selectedQuestion = _selectedQuestion;

And then refer to it as _selectedQuestion. This prevents accidentally writing selectedQuestion when you meant self.selectedQuestion.

However, Apple recommend against using underscore. You can use another name, but @Sherm's method is the best, imho.

Solution 5

Simply @synthesize the desired property in your subclass, then you can use that as the name to access the property directly:

Main Class interface:

@interface AClass : NSObject

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

@end

Subclass interface:

@interface BCLass : AClass
@end

Subclass implementation:

@implementation BCLass

@synthesize delegate = _delegate;

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

@end
Share:
28,600
Marcin
Author by

Marcin

Passionate developer. iOS. https://github.com/krzyzanowskim

Updated on March 15, 2020

Comments

  • Marcin
    Marcin over 4 years

    There is Class A with:

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

    then I have subclass

    @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
    

    and this is infinite loop because setProp1 from ClassB calls [ClassB setProp1:val] from within ClassB.

    I've already tried call [super setProp1] but this

    How to overwrite @property and assign value inside overwritten setter ? And let's assume I can't modify ClassA.

  • Marcin
    Marcin about 13 years
    example is just for example purpose.
  • bbum
    bbum about 13 years
    No need for the self-> part unless using GCC 4.2.
  • Sherm Pendley
    Sherm Pendley about 13 years
    True, but AFAIK it does no harm, and it serves as a visual reminder that I'm doing something a bit out of the ordinary, accessing an ivar without going through its accessor method.
  • Daniel
    Daniel almost 12 years
    This didn't work out for me, please check out my solution: stackoverflow.com/a/12465444/662605
  • RileyE
    RileyE over 11 years
    @Daniel You have exactly what he has.
  • pancake
    pancake almost 10 years
    you should only do this for a retain property, the OP's example is an assign property.
  • LargeGlasses
    LargeGlasses over 8 years
    The part that saved me was You shouldn't use "self" inside the setter since that creates the recursive call. Once I replaced self. with an underscore, the magic took place.
  • josephrider
    josephrider almost 8 years
    @ShermPendley Personally, I don't need a visual reminder when I'm IN the accessor block. It's like adding a sign for TOILET over the toilet. EDIT: unless of course alcohol is involved, then both may be necessary. ;)