我有以下代码:
// 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
我这样调用上面的代码:
ClassB *b = [[ClassB alloc] init];
[b debug];
输出为1
。如果我将-[Class A debug]
方法更改为使用self.my_property
,则输出为2
。
我(有限)的理解是,使用“现代”Objective-C运行时,类ivars是动态生成的。具有这些动态生成的ivars的类的子类可以访问所述实例变量吗?如果我在ClassB.m中没有包含@synthesize my_property
行,编译器会给出错误:
错误:'struct ClassB'没有名为'my_property'的成员
但是,如果我将-[ClassB init]
方法更改为使用属性表示法而不是ivar表示法,它将识别继承的属性,尽管由于它是只读的而不允许我写入它。如何在向我的API的消费者维护其只读状态的同时写入它?
澄清:有几个答案指出我可以使用香草伊娃。这确实是正确的,但面向公众的@interface
揭示了最好保密的实施细节。与this post on SO中一样:
我更喜欢面向公众的界面尽可能小而干净,只是揭示了我班级中相关的方面。
答案 0 :(得分:2)
我的猜测是,如果你在ClassA.h中明确声明了ivar,它将按预期工作。你不需要ClassB.m中的@synthesize,你可以像往常一样使用箭头符号和带点符号的属性访问。
答案 1 :(得分:1)
在界面中,您可以使用@private
将变量声明为私有。您仍然可以将其设为只读属性。除非我误解你的意图,否则就会这样做。您可以在类内部以及从后代类中访问它,但外部用户只能读取它。
答案 2 :(得分:0)
如果要覆盖放入my_property的值,正确的方法是让A类的初始化程序具有my_property值的参数。即。
// 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