I have a doubt regarding property redeclaration
Overview:
Points to note: - Memory management = ARC (Automatic Reference Counting)
Question:
Code: (in separate files)
A.h
#import<Foundation/Foundation.h>
@interface A : NSObject
@property (readonly) int n1;
- (void) display;
@end
A.m
#import "A.h"
@implementation A
@synthesize n1 = _n1;
- (void) display
{
printf("_n1 = %i\n", _n1); //I expected _n1 and self.n1 to display the same value
printf("self.n1 = %i\n\n", self.n1); //but they seem to display different values
}
@end
B.h
#import"A.h"
@interface B : A
@property (readwrite) int n1;
@end
B.m
#import"B.h"
@implementation B
@synthesize n1 = _n1;
@end
test.m
#import"B.h"
int main()
{
system("clear");
B* b1 = [[B alloc] init];
b1.n1 = 20;
[b1 display]; //Doubt - my expected behavior is different from actual behavior
return(0);
}
Expected Behavior:
_n1 = 20
self.n1 = 20
Actual Behavior:
_n1 = 0
self.n1 = 20
There are two ways of going about this. In neither case do you call @synthesize
in the subclass. I'm surprised that compiles for you. I would expect an error like "Property 'n1' attempting to use ivar '_n1' declared in superclass 'A'". In any case it's definitely not something you can really do, which is why you're seeing strange behavior. (I remembered why you aren't seeing this error; it's because of the separate compile units. You're just winding up with different ivars.)
First, you need to understand @dyanmic
. This is a way of telling the compiler "yes, I know you don't see an implementation for the required method here; I promise it'll be there at runtime." In the subclass, you will use @dynamic
to let the compiler know that it's ok to inherit n1
.
@implementation B
@dynamic n1;
@end
Now, you need to provide the setN1:
method. IMO, subclasses shouldn't go messing with their superclass's ivars, so I approve of the fact that synthesized ivars are marked @private
. In a second, I'll tell you how to undo that, but for now let's deal with my preferred solution:
setN1:
as a private method in A
.B
.A.h
@interface A : NSObject
@property (readonly) int n1;
- (void) display;
@end
A.m
#import "A.h"
@interface A () // Private class extension, causes setN1: to be created but not exposed.
@property (readwrite) int n1;
@end
@implementation A
@synthesize n1 = _n1;
- (void) display {
...
}
@end
B.h
#import "A.h"
@interface B : A
@property (readwrite) int n1; // Tell the world about setN1:
@end
B.m
#import "B.h"
@implementation B
@dynamic n1; // Yes compiler, setN1: exists. I promise.
@end
Now, some people think it's fine for subclasses to mess with their superclass's ivars. Those people are wrong (ok, IMHO...) but it is possible in ObjC. You just need to declare the ivar @protected
. This is the default when you declare ivars directly in the @interface
(one of many reasons you shouldn't do this anymore). It would look like this:
A.h
@interface A : NSObject {
int _n1;
}
...
A.m -- remove the extra class extension that makes n1 writable in the superclass.
B.h -- no change
B.m
@implementation B
@dynamic n1;
- (void)setN1:(int)n1 {
_n1 = n1;
}
@end