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

git*_*rik 28 cocoa objective-c synthesize

如果我理解正确,在Objective-C中,属性会自动与getter和setter合成,实例变量声明为属性名称,并带有下划线prepended(_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;

    }

}
Run Code Online (Sandbox Code Playgroud)

hello.h

#import <Foundation/Foundation.h>

@interface Hello : NSObject
@property (copy, nonatomic) NSString *myString;
@end
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

可以像这样编译和运行:

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
Run Code Online (Sandbox Code Playgroud)

现在当我将myString属性更改为只读时:

@property (readonly, copy, nonatomic) NSString *myString;
Run Code Online (Sandbox Code Playgroud)

然后,当我尝试编译时,我收到一个错误:

hello.m:11:9: error: unknown type name '_myString'; did you mean 'NSString'?
        _myString = @"Hello";
        ^~~~~~~~~
        NSString
Run Code Online (Sandbox Code Playgroud)

所以_myString没有定义.编译器没有用实例变量_myString合成属性吗?当我自己合成它时,让我们看看它是否有效:

在hello.m实现中:

@synthesize myString = _myString;
Run Code Online (Sandbox Code Playgroud)

现在再次运作:

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
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是,当你使用readonly属性时,为什么它不能用下划线ivar自动合成?或者我完全错误地了解这个Objective-C的工作原理是什么?

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

先感谢您.

Mar*_*n R 55

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

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

  • 我只想补充一下为什么Apple会这样做的可能理由.因为如果同时实现getter和setter(或者只是readonly属性的getter),obj-c无法知道你打算使用iVar实现属性,也不知道你是否使用iVar的类型.例如,有一个未使用的指针iVar将为每个对象浪费4或8个字节. (7认同)
  • 严格地说,Objective-C不做编译的综合. (5认同)