如果我理解正确,在Objective-C中,属性会自动与getter和setter合成,实例变量声明为属性名称,前缀为下划线(_ivar
)。
所以,这段代码:
#import <Foundation/Foundation.h>
#import "hello.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
Hello *hello = [[Hello alloc] init];
NSLog(@"%@", hello.myString);
return 0;
}
}
#import <Foundation/Foundation.h>
@interface Hello : NSObject
@property (copy, nonatomic) NSString *myString;
@end
#import "hello.h"
@implementation Hello
-(Hello *)init
{
if (self = [super init]) {
_myString = @"Hello";
}
return self;
}
-(NSString *)myString
{
return [NSString stringWithFormat:@"%@ %@", _myString, @"World"];
}
@end
可以像这样编译和运行:
bash-3.2$ clang -framework Foundation main.m hello.m -o hello
bash-3.2$ ./hello
2013-05-27 13:20:39.738 hello[23320:707] Hello World
现在,当我将myString属性更改为readonly时:
@property (readonly, copy, nonatomic) NSString *myString;
然后当我尝试编译时出现错误:
hello.m:11:9: error: unknown type name '_myString'; did you mean 'NSString'?
_myString = @"Hello";
^~~~~~~~~
NSString
因此未定义_myString
。编译器没有用实例变量_myString合成属性吗?当我自己合成它时,让我们看看它是否有效:
在hello.m实现中:
@synthesize myString = _myString;
现在再次运作:
bash-3.2$ clang -framework Foundation main.m hello.m -o hello
bash-3.2$ ./hello
2013-05-27 13:36:59.916 hello[24219:707] Hello World
所以,我的问题是,当你在属性上使用readonly
时,为什么不能用下划线ivar自动合成?或者我完全错误地了解这个Objective-C的工作原理是什么?
我非常感谢一个解释性答案,因为我真的想了解究竟发生了什么以及为什么。
提前谢谢。
答案 0 :(得分:55)
如果实现所有必需的访问器方法(getter用于只读属性,getter + setter用于读写属性),则属性不会自动合成。
因为您为只读属性实现了getter方法-(NSString *)myString
,
它不是自动合成的。如果你的getter需要一个实例变量来备份属性值,你必须添加synthesize语句(就像你做的那样)或实例变量。