17

当您在 Xcode 中选择拆分视图应用程序时,我正在使用标准示例拆分视图,添加一些字段后,我需要添加一些字段以在详细视图中显示它们。

在原始示例中发生了一些有趣的事情,主视图在详细视图中设置了“detailItem”属性,详细视图显示它。

- (void)setDetailItem:(id) newDetailItem
{
if (_detailItem != newDetailItem) {
    _detailItem = newDetailItem;

    // Update the view.
    [self configureView];
}

我明白那是什么,所以当我在玩它的时候。我认为如果我使用 self.detailItem 而不是 _detailItem 会是一样的,因为它是类的属性。

然而,当我使用

self.detailItem != newDetailItem

我实际上陷入了一个不断调用此方法的循环中,而我无法在模拟器中执行任何其他操作。

我的问题是,下划线变量(ivar?)和属性之间的实际区别是什么?我在这里阅读了一些帖子,这似乎只是一些客观的 C 约定,但实际上有所不同。

4

4 回答 4

41

_property表示您正在直接访问该属性。

self.property表示您正在使用访问器。

在您的情况下,在您调用它的 setter 方法中,创建一个递归调用。

于 2012-12-08T11:02:08.330 回答
6

在您的实验过程中,您设置了一个无限循环,这就是模拟器无响应的原因。

在调用self.detailItem范围内递归setDetailItem:调用,setDetailItem:因为您的类实现了属性的自定义设置方法detailItem

我会向您推荐有关属性、ivars 等独家新闻的Apple 文档中的声明属性;但简而言之,声明的属性是为您的类提供访问器方法的一种简化方式。无需编写您自己的访问器方法(就像我们在 Objective-C 2.0 之前必须做的那样),它们现在是通过属性语法为您生成的。

于 2012-12-08T11:01:57.287 回答
5

这些属性基本上是编译器为给定实例变量生成settergetter的一种方式。

所以当你使用类似的东西时:

id detailItem = self.detailItem;

你在幕后做的是:

id detailItem = [self detailItem];

同样适用于:

self.detailItem = otherDetailItem;

将会:

[self setDetailItem:otherDetailItem];

因此,当您自己编写 setter 时,您会陷入无限循环,因为您访问的是方法本身。你可以自由地使用“自我”。你的类中的符号,而不是当你因为我上面描述的机制而覆盖设置器或访问器时。

我使用 . 简单访问 ivar 的符号是当我更改值时,您永远不知道在您的类中更改值时需要发生什么。你有什么关于状态的东西应该通知一些代表状态改变了吗?但是,通常情况并非如此,只需使用 . 表示您确保将来如果您决定在您的 setter 方法中做一些魔术,您将不必重构某些代码。

于 2012-12-08T11:01:57.617 回答
2

我将举一个例子(不启用 ARC):

@property (nonatomic, retain) NSNumber* number;

如果你不合成它,你可以这样访问它:

self.number= [NSNumber numberWithBool: YES];

在这种情况下,数字被保留。如果您合成它并且不使用该属性:

@synthesize number;

稍后在文件中:

number=[NSNUmber numberWithBool: YES];

您尚未使用该属性,因此不会保留该数字。这在使用访问器和合成属性之间存在相关差异。

于 2012-12-08T13:02:57.983 回答