anhdat
anhdat

Reputation: 465

Objective C - Custom Getter with inheritance

Recently I have worked with Core Data. When I want to set a default value for some fields, I came up with this problem:

So I made a simple represent:

We have 2 class Parent and Child, in which Child inherit from Parent.

// Parent.h
@interface Parent : NSObject
@property (strong, nonatomic) NSString *lastName;



// Child.h
@interface Child : Parent

In Parent class, I made a custom getter to set a default value when nothing is set:

// Parent.h
- (NSString *)lastName
{
    if (_lastName) {
        return _lastName;
    } else {
        return @"Parent Default Name";
    }
}

But I cannot make a custom default value for the field "name" which Child inherits from its Parent.

// Child.h
@implementation Child

- (NSString *)lastName
{
    if (super.lastName) {
        return super.lastName;
    } else {
        return @"Child Default Name";
    }
}

The main function to test: int main(int argc, const char * argv[]) {

    @autoreleasepool {
        Parent *newParent = [[Parent alloc] init];
        newParent.lastName = @"newParentName";
        NSLog(@"Parent: %@", newParent.lastName);

        Child *newChild =  [[Child alloc] init];
        NSLog(@"Child: %@", newChild.lastName);
    }
    return 0;
}

Apparently, @"Child Default Name" is never reach. The returned values would be @"Parent Default Name". So my question here is: How can I set a custom getter for the field the Child class inherits from Parent without define an overriding property?

Upvotes: 2

Views: 656

Answers (3)

user3386109
user3386109

Reputation: 34829

The problem is that the parent implementation of the lastName method never returns nil. It either returns the current (non-nil) value of _lastName or it returns the default parent string. In neither case does it return nil. Hence the if [super.lastName] check will always return true.

To avoid the problem, the child getter needs to access the instance variable directly. This can only be done if the parent class explicitly declares the instance variable in the header file. So parent.h should be

@interface Parent : NSObject
{
    NSString *_lastName;
}
@property (strong, nonatomic) NSString *lastname;
@end

and then the implementation in child.m can be

- (NSString *)lastname
{
    if ( _lastName )
        return( _lastName );
    else
        return  @"Child default name";
}

Upvotes: 0

simalone
simalone

Reputation: 2768

// Parent.h

@interface Parent : NSObject
{
   NSString *_lastName; //just add this line.
}


@property (strong, nonatomic) NSString *lastName;

If you want another name to use, you can try this:

// Parent.h
@interface Parent : NSObject
{
   NSString *_lastNameAlias; //can be used in child
}


@property (strong, nonatomic) NSString *lastName;

//Parent.m
@synthesize lastName = _lastNameAlias;

// Parent.m

- (NSString *)lastName
{
    if (!_lastName) {
        _lastName =  @"Parent Default Name";
    } 

    return _lastName;
}

// Child.m

- (NSString *)lastName
{
    if (!_lastName) { //Or _lastNameAlias
        _lastName =  @"Child Default Name";
    } 

    return _lastName;
}

And as Steven Fisher mentioned, lastname is different with lastName, but I think it is a spelling mistake.

Upvotes: 2

Steven Fisher
Steven Fisher

Reputation: 44876

Note:

- (NSString *)lastname

vs

- (NSString *)lastName

Objective-C is case sensitive. Make sure they have the same case and the behaviour you want should happen automatically.

That said, calling self.lastName is pretty weird (assuming you settle on lastName for both). I'm not sure that will work. I suggest calling [super lastName] instead.

Upvotes: 0

Related Questions