Question

I've recently realized that it is not proper form to access the properties of a class from inside the init using self.whatever = thing, and that you should instead access the properties directly using _whatever = thing. This works fine when I'm setting values for a base class. However, when I try to set values inside the init of a subclass, I get the error "Use of undeclared identifier _whatever". Using self.whatever from inside the init of the subclass works fine.

Just for clarity, for @property int whatever declared in the interface of a base object, this compiles:

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

        self.whatever = 100;
    }
    return self;
}

And this doesn't:

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

        _whatever = 100;
    }
    return self;
}

I think I am misunderstanding something here. I tried searching for what I'm doing wrong, but I don't know the right words to search for.

As requested, the header for the base class:

#import <Foundation/Foundation.h>

@interface DTCharacter : NSObject

@property BOOL isIdle;

@end

I'm using auto synthesize so there is nothing about this variable in the implementation of the base class.

Also the header file of the subclass does not mention or reference the variable.

I'm trying to assign it here in the implementation of the subclass:

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

    if (self) {
        [self createName];

        _isIdle = YES;  //says use of undeclared identifier
        //this would work: self.isIdle = YES;
    }
return self;
}
Was it helpful?

Solution

Accessing properties in init or dealloc can be problematic if the property accessor methods make assumptions about the state of the object, which might not be fulfilled in a partially constructed object.

But this applies only to the properties of the class itself, not to the properties of the superclass. After

self = [super init];

the "super-part" of self is fully constructed, therefore it is safe to call

self.whatever = 100;

in the subclass init method, to set a property declared in the superclass.

_whatever = 100;

does not work in the subclass because the automatically synthesized instance variable is visible only in the superclass itself. You could declare it explicitly to make it visible to the subclass, but there is no need to do so.

OTHER TIPS

Martin's answer is the best, in that you really don't need to do this for superclass properties (and arguably should not, on the theory that class implementations should be private, even from subclasses, to the extent possible). However, if you do want to do it, here's an example to show how:

main.m:

#import <Foundation/Foundation.h>
#import "PGRBase.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        PGRChild * theObject = [PGRChild new];
        NSLog(@"Property is %d\n", theObject.prop);

    }
    return 0;
}

PGRBase.h:

#import <Foundation/Foundation.h>

@interface PGRBase : NSObject {
    int _prop;
}

@property (readwrite, nonatomic, assign) int prop;

@end

@interface PGRChild : PGRBase

@end

PGRBase.m:

#import "PGRBase.h"

@implementation PGRBase

- (instancetype)init
{
    self = [super init];
    if ( self ) {
        _prop = 1;
    }
    return self;
}

@end

@implementation PGRChild

- (instancetype)init
{
    self = [super init];
    if ( self ) {
        _prop = 2;
    }
    return self;
}

@end

The NSLog() call logs Property is 2.

There is code snippet how make ivars accessible for child classes:

@interface SomeBase : NSObject
{
@protected
    WhateverType* _whatever;
}
@end

so _whatever will be visible for child classes of SomeBase.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top