26

In the superclass MyClass:

@interface MyClass : NSObject

@property (nonatomic, strong, readonly) NSString *pString;

@end

@implementation MyClass

@synthesize pString = _pString;

@end

In the subclass MySubclass

@interface MySubclass : MyClass

@end

@implementation MySubclass

- (id)init {
    if (self = [super init]) {
        _pString = @"Some string";
    }
    return self;
}

The problem is that the compiler doesn't think that _pString is a member of MySubclass, but I have no problem accessing it in MyClass.

What am I missing?

2
  • try [super setPString:] or [self setPString:] Commented Jun 8, 2012 at 4:27
  • 1
    tried to remove readonly property like below @property (nonatomic, strong) NSString *pString; Commented Jun 8, 2012 at 4:31

3 Answers 3

54

The instance variable _pString produced by @synthesize is private to MyClass. You need to make it protected in order for MySubclass to be able to access it.

Add an ivar declaration for _pString in the @protected section of MyClass, like this:

@interface MyClass : NSObject {
    @protected
    NSString *_pString;
}

@property (nonatomic, strong, readonly) NSString *pString;

@end

Now synthesize the accessors as usual, and your variable will become accessible to your subclass.

Sign up to request clarification or add additional context in comments.

6 Comments

Yes, you will...if it is from a subclass that has access to the underlying variable.
@Owl You will not be able to set the string through the property, but you will be able to set the string to the backing variable, which will have the effect of pString property changing its value. You need to set _pString = @"abc", not self.pString = @"abc".
@Owl what dasblinken said! You don't HAVE to set the variable through its property interface. This way objects that don't inherit from the class cannot change the variable. It is readonly except to children.
Good answer. I would personally use a double under score to indicate that you are accessing a protected ivar on a superclass and explicitly @synthesize it:
A small reminder: in the subclass use the ivar (_myVariable) instead of the accessor (self.myVariable).
|
5

I am familiar with this problem. You synthesize the variable in your .m class, so it is not imported along with the header since the _pString variable will be created as part of the implementation, and not the interface. The solution is to declare _pString in your header interface and then synthesize it anyway (it will use the existing variable instead of creating a private one).

@interface MyClass : NSObject
{
    NSString *_pString; //Don't worry, it will not be public
}

@property (nonatomic, strong, readonly) NSString *pString;

@end

Comments

0

The given answer works perfectly fine. This is an alternative answer, that apparently Apple likes a bit more.

You can define a private extension of your class, a MyClass+Protected.h file, which needs to be included in MyClass.m and MySubclass.m.

Then, in this new file, you redefine the property as readwrite.

@interface MyClass ()
@property (strong, readwrite) NSString * pString;
@end

This alternative allows you to use the accessor self.pString rather than the ivar _pString.

Note: you still need to keep the definition of pString in your MyClass.h as is.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.