Iphone 理解属性访问概念的问题

Iphone 理解属性访问概念的问题,iphone,objective-c,ios,Iphone,Objective C,Ios,我最近开始开发一款iPhone应用程序。来自C#,Objective-C给了我一些陷阱。我不明白以下片段中发生了什么: @interface RootViewController : UITableViewController { NSString *simpleProperty; NSString *propertyWithUnderscoreIvar; } @property (nonatomic, retain) NSString *simpleProperty; @pr

我最近开始开发一款iPhone应用程序。来自C#,Objective-C给了我一些陷阱。我不明白以下片段中发生了什么:

@interface RootViewController : UITableViewController {
    NSString *simpleProperty;
    NSString *propertyWithUnderscoreIvar;
}

@property (nonatomic, retain) NSString *simpleProperty;
@property (nonatomic, retain) NSString *propertyWithUnderscoreIvar;

@end

@implementation RootViewController

@synthesize simpleProperty;
@synthesize propertyWithUnderscoreIvar = _propertyWithUnderscoreIvar;

- (NSString *)simpleProperty {
    return @"Simple property value";
}
- (NSString *)propertyWithUnderscoreIvar {
    return @"Property with underscore value";
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog([NSString stringWithFormat:@"%i %@", 1, simpleProperty]);
    // --> 1 (null)

    NSLog([NSString stringWithFormat:@"%i %@", 2, propertyWithUnderscoreIvar]);
    // --> 2 (null)

    NSLog([NSString stringWithFormat:@"%i %@", 3, _propertyWithUnderscoreIvar]);
    // --> 3 (null)

    NSLog([NSString stringWithFormat:@"%i %@", 4, self.simpleProperty]);
    // --> 4 Simple property value

    NSLog([NSString stringWithFormat:@"%i %@", 5, self.propertyWithUnderscoreIvar]);
    // --> 5 Property with underscore value
}

为什么前三个输出为空?我自己的属性实现是否不正确?

在viewDidLoad方法中,您记录的是实例变量(IVAR)的值,而不是属性。从上面的代码示例中:

@interface RootViewController : UITableViewController {
     NSString *simpleProperty;
     NSString *propertyWithUnderscoreIvar;
}
这在类中声明了两个变量——simpleProperty和PropertyWithUnderlineIvar。另一方面,以下代码声明属性:

@property (nonatomic, retain) NSString *simpleProperty;
@property (nonatomic, retain) NSString *propertyWithUnderscoreIvar;
这些只是声明。Objective C与C#有些相似,因为它提供了为类属性生成getter和setter的简单方法。在Objective-C中,这是通过
@synthesis
关键字完成的(这大致类似于C#automatic properties)

实现文件中的@synthesis关键字为您的属性创建getter和setter方法。您的第一个合成看起来不错,它将为“simpleProperty”创建一个getter和setter,由同名的实例变量支持。你的第二个@synthesis是hokey。它将为“PropertyWithUnderlineIvar”创建一个getter和setter,由您从未声明过的实例变量“\u PropertyWithUnderlineIvar”支持。这段代码可以在现代运行时工作,但不能在传统运行时工作(请注意,即使在现代运行时,@synthesis也会忽略您的'propertyWithUnderlineIvar'ivar)

至于您的代码为什么要打印空值,请在日志代码中执行以下操作:

NSLog([NSString stringWithFormat:@"%i %@", 1, simpleProperty]);
这是直接访问实例变量。但此时还没有将实例变量设置为任何值。您真正想做的是访问该属性,如下所示:

NSLog([NSString stringWithFormat:@"%i %@", 1, [self simpleProperty]);
改为使用
[self simpleProperty]
将调用方法
simpleProperty
并返回硬编码的值,这正是您试图执行的操作。

- (NSString *)simpleProperty {
    return @"Simple property value";
}
- (NSString *)propertyWithUnderscoreIvar {
    return @"Property with underscore value";
}
是访问者。在

NSLog([NSString stringWithFormat:@"%i %@", 1, simpleProperty]);
您正在直接访问ivar。因此,这些IVAR是空的,因为您没有对它们进行任何设置。在

NSLog([NSString stringWithFormat:@"%i %@", 4, self.simpleProperty]);

您正在通过访问器访问ivar。因此,运行库调用您的访问器。在我看来,当您使用
@synthesis
时,您不应该编写自己的访问器。至少当你刚开始用Objective C写的时候。另外,你的访问者有点奇怪

为了访问getter/setter方法,您应该使用
self
或任何
实例

NSLog([NSString stringWithFormat:@"%i %@", 1, self.simpleProperty]);

上面的一行将按照您的预期打印出
@“简单属性值”

但我没有声明任何实例变量。只有1个隐式声明:
@synthesis-propertyWithUnderlineAivar=\u-propertyWithUnderlineAivar你的@synthesis为你的属性创建实例变量。它必须把它们存储在某个地方。@Sandro-你发表评论时我正在编辑。查看扩展答案,了解您在哪里声明IVAR。我看到了,谢谢。我把片段重写了一点。现在我没有在实例变量中使用下划线前缀?这是一种编码实践,有助于区分ivar和属性,并有助于避免您遇到的相同问题(在您真正打算使用属性时意外使用ivar)。我甚至需要ivar吗?当我只使用属性时,我不必区分IVAR和属性……使用IVAR有一些优势,即使在现代运行时也是如此。但最终这取决于你自己。FWIW,似乎没有人提到他可以调用
NSLog(@“%i:%@”,1,self.simpleProperty)直接。没有必要使用
[NSString stringWithFormat:…]
,因为
NSLog()
在内部已经做了类似的事情(我想)。
NSLog([NSString stringWithFormat:@"%i %@", 1, self.simpleProperty]);