Objective-C - 只用下划线ivar合成的readonly属性?

时间:2013-05-27 11:41:37

标签: objective-c cocoa synthesize

如果我理解正确,在Objective-C中,属性会自动与getter和setter合成,实例变量声明为属性名称,前缀为下划线(_ivar)。

所以,这段代码:

的main.m

#import <Foundation/Foundation.h>
#import "hello.h"

int main(int argc, char *argv[])
{

    @autoreleasepool {

        Hello *hello = [[Hello alloc] init];
        NSLog(@"%@", hello.myString);

        return 0;

    }

}

hello.h

#import <Foundation/Foundation.h>

@interface Hello : NSObject
@property (copy, nonatomic) NSString *myString;
@end

hello.m

#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的工作原理是什么?

我非常感谢一个解释性答案,因为我真的想了解究竟发生了什么以及为什么。

提前谢谢。

1 个答案:

答案 0 :(得分:55)

如果实现所有必需的访问器方法(getter用于只读属性,getter + setter用于读写属性),则属性不会自动合成

因为您为只读属性实现了getter方法-(NSString *)myString, 它不是自动合成的。如果你的getter需要一个实例变量来备份属性值,你必须添加synthesize语句(就像你做的那样)或实例变量。