我在使用属性时发现了一种奇怪的行为,它继承为readonly而不是在继承的类中重新声明为readwrite
在 A.h
中@interface A : NSObject
@property (nonatomic, strong, readonly) NSObject * someProperty;
@end
在 B.h
中@interface B : A
// no matter if here
// @property (nonatomic, strong, readwrite) NSObject * someProperty;
- (void)foo;
@end
在 B.m
中@interface B()
// no matter if here
@property (nonatomic, strong, readwrite) NSObject * someProperty;
@end
@implementation B
- (void)foo {
NSLog(@"%@", self.someProperty);
// crash here with unrecognized selector setSomeProperty:
self.someProperty = [NSObject new];
}
@end
致电
self.someProperty = [NSObject new];
导致代码在无法识别的选择器“setSomeProperty:”上崩溃
调查显示,即使宣布为readwrite,看起来setter也没有得到合成
为什么会这样?编译器没有表明发生这种情况的任何警告,也没有发现任何记录此行为的地方
答案 0 :(得分:2)
向B.m文件添加@synthesize
指令,崩溃将消失:
@synthesize someProperty = _someProperty;
问题在于,在父类中,您将属性声明为readonly
,因此没有为其合成的setter。子类继承了这种行为。即使您将属性重新声明为子类中的readwrite
。
@synthesize
命令将指示编译器再次为类B生成访问器方法。
希望这有帮助!
答案 1 :(得分:2)
我不能给你一个官方参考,但这是我所经历的:对于从超类继承的属性,编译器不会生成任何访问器方法。< / p>
在您的情况下,该属性在A类中声明为 因此子类中的属性声明只是对编译器的“承诺”
getter和setter函数将在运行时可用(类似于@dynamic声明)。
如果没有setter,那么你将获得运行时异常。 因此,在子类中重新声明属性的用例将是超类
在 public 接口中将该属性声明为只读,但在。中以读写方式声明
(私人)类扩展名: 在这种情况下,setter和getter都是在A类和B类中创建的
可以在其实现中将该属性重新声明为读写。readonly
,以便编译器创建
只有一个getter方法。 B类中的重新声明不会创建任何其他访问者
方法。原因可能是B类不知道在A类中如何实现属性(它不必是实例变量)。// A.h
@interface A : NSObject
@property (nonatomic, strong, readonly) NSObject * someProperty;
@end
// A.m
@interface A()
@property (nonatomic, strong, readwrite) NSObject * someProperty;
@end
@implementation A
@end