Saturday, November 03, 2012

How to access backing ivars for inherited properties in Objective-C

I had a superclass that declared and synthesized a read only property, meant to be set in its subclasses. The code was something like this:


@interface A : NSObject
@property (nonatomic, readonly) NSUInteger prop;
@end

@implementation A
@synthesize prop = _prop;
@end

@interface B : A
@end

@implementation B

- (void)establishValueForProp
{
    _prop = 1// PROBLEM !!!
}

@end


The instance variable backing the property seemed to be invisible in the subclass. The error was pretty unclear when compiling an iOS app: "Use of undeclared identifier '_prop'".  To get around the error I did the following:


@interface A : NSObject {
    NSUInteger _prop;
}
@property (nonatomic, readonly) NSUInteger prop;
@end


That is, I explicitly declared the backing variable in the declaration of the superclass.

Interestingly, when I was preparing this blog post I compiled the code above as a "Command Line Tool" type of project, not an iOS app. The error was different, dare I say better, more telling of the root cause: "Instance variable '_prop' is private". So it's a matter of the visibility of the ivar, so perhaps a better fix would be:


@interface A : NSObject {
    @protected
    NSUInteger _prop;
}
@property (nonatomic, readonly) NSUInteger prop;
@end


Kind of interesting though that properties are synthesized by default as private ivars. Learned something new.

1 comment:

Liviu Macsen said...

Thank your Bogdan for your solution. I found that you can also synthesize in subclass in order to solve this problem.


@implementation B

@synthesize prop = _prop;

- (void)establishValueForProp
{
_prop = 1; // Working !!!
}

@end