29

如果我理解正确,在 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;

    }

}

你好.h

#import <Foundation/Foundation.h>

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

你好.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 属性更改为只读时,如下所示:

@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 的东西是如何工作的?

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

先感谢您。

4

1 回答 1

55

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

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

于 2013-05-27T11:54:36.287 回答