Objective-C 2.0: Inheriting synthesised instance variables
I have the following code:
// ClassA.h
@interface ClassA : NSObject
@property (nonatomic, retain, readonly) id my_property;
@end
// ClassA.m
@implementation ClassA
@synthesize my_property;
- (id)init {
if (self = [super init]) {
self->my_property = [NSNumber numberWithInt:1];
}
return self;
}
- (void)debug {
NSLog(@"%@", self->my_property);
}
@end
// ClassB.h
#import "ClassA.h"
@interface ClassB : ClassA
@end
// ClassB.m
#import "ClassB.h"
@implementation ClassB
@synthesize my_property;
- (id)init {
if (self = [super init]) {
self->my_property = [NSNumber numberWithInt:2];
}
return self;
}
@end
I call the above code like so:
ClassB *b = [[ClassB alloc] init];
[b debug];
The output is 1
. If I change the -[Class A debug]
method to use self.my_property
, the output is 2
.
My (limited) understanding is that with the "modern" Objective-C runtime, class ivars are generated dynamically. Can subclasses of classes with these dynamically-generated ivars access said instance variables? If I do not include the @synthesize my_property
line in ClassB.m, the compiler gives me the error:
error: 'struct ClassB' has no member named 'my_property'
However, if I change the -[ClassB init]
method to use property notation rather than ivar notation, it will recognise the inherited property, albeit not let me write to it on account of it being read-only. How can I write to it while maintaining its read-only state to consumers of my API?
Clarification: A couple of answ开发者_运维知识库ers have pointed out that I can use vanilla ivars. That is indeed correct, but then the public-facing @interface
reveals implementation details that are best kept private. As in this post on SO:
I prefer my public-facing interfaces to be as minimal and clean as possible, only revealing aspects of my class that are pertinent.
My guess is that if you declare the ivar explicitly in ClassA.h, it will work as expected. You will not need the @synthesize in ClassB.m, and you will be able to access the ivar with arrow notation and the property with dot notation as usual.
In your interface, you can declare your variable as private with @private
. You can still make it a read-only property. Unless I am misunderstanding your intent, this would do it. You can access it inside your class, and from inside descendant classes, but outside users can only read it.
If you want to override the value put in to my_property, the correct way is for the initialiser for class A to have a parameter that is the value of my_property. i.e.
// ClassA.h
@interface ClassA : NSObject
@property (nonatomic, retain, readonly) id my_property;
// designated initialiser
-(id) initWithMyProperty: (NSNumber*) newMyProperty;
@end
// ClassA.m
@implementation ClassA
@synthesize my_property;
- (id)initWithMyProperty: (NSNumber*) newMyProperty
{
if (self = [super init])
{
my_property = [newMyProperty retain];
}
return self;
}
-(id) init
{
return [self initWithMyProperty: [NSNumber numberWithInt: 1]];
}
-(void) dealloc
{
[my_property release];
[super dealloc];
}
...
@end
// ClassB.m
#import "ClassB.h"
@implementation ClassB
- (id)init
{
if (self = [super initWithMyProperty: [NSNumber numberWithInt:2]])
{
// Any other initialisation
}
return self;
}
@end
精彩评论