Reputation: 465
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
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
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
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