在目标c中使用ivars vs属性的原因

Cal*_*YSR 21 properties objective-c ivar

我一直无法找到关于这个主题的任何信息,而且我所知道的大部分内容都是完全意外发生的(并且几个小时试图找出我的代码无效的原因).在学习objective-c的大多数教程时,我发现使用相同的名称创建变量和属性.我不明白它的意义,因为看起来该属性完成了所有的工作,变量只是坐在那里.例如:

Test.h

@interface Test : NSObject {
    int _timesPlayed, _highscore;
}

@property int timesPlayed, highscore;

// Methods and stuff

@end
Run Code Online (Sandbox Code Playgroud)

Test.m

@implementation Test

  @synthesize timesPlayed = _timesPlayed;
  @synthesize highscore   = _highscore;

  // methods and stuff

@end
Run Code Online (Sandbox Code Playgroud)

我知道的

1)好的,今天我发现(经过几个小时的混乱),无论你对属性做了多少改变,highscore = 5091231当你试图调用[测试高分]时它不会改变任何东西,因为它仍将返回_highscore的值(我认为)是在test.h中设置的ivar.因此,test.m中所有变量的变化都需要改变_highscore而不是highscore.(如果我错了,请纠正我)

2)如果我理解正确(我可能不这样做),test.h中设置的ivars代表实际内存,因为@properties只是访问该内存的方式.因此,在实现之外,我无法通过该属性访问_highscore.

我不明白

基本上我不了解这种情况是我是否需要使用ivars或者我是否可以使用@property和@synthesize.似乎ivars只是额外的代码,除了让我困惑之外什么都不做.我见过的一些最近的tuts似乎没有使用ivars,但有些人做了.那么这只是编码偏好的事情还是实际上很重要?我试过通过Apple的文档搜索,但我在那里相当迷失,似乎永远不会找到我正在寻找的东西.任何指导将不胜感激.

Dav*_*ist 36

您可以将合成属性的语法视为@synthesize propertyName = variableName.

这意味着如果您编写@synthesize highscore = _highscore;一个新的ivar,_highscore将为您创建名称.因此,如果您希望通过转到_highscore变量来直接访问属性存储的变量.

一些背景

在某些版本的编译器之前,我不记得合成语句没有创建ivar.相反,它只说它应该使用什么变量,所以你必须声明变量和属性.如果使用下划线前缀合成,那么您的变量需要具有相同的前缀.现在你不必再自己创建变量,而是创建一个variableName你在合成语句中指定的变量(如果你自己没有声明它,在这种情况下它只是用作后缀变量)财产).

你的代码在做什么

highscore在声明变量时显式创建了一个ivar ,然后隐式创建了_highscore在合成属性时调用的另一个ivar .这些变量不是同一个变量,因此更改其中一个变量不会改变另一个变量.

你应该使用变量吗?

这真的是一个关于偏好的问题.

专业变量

有些人认为如果你不必self.在整个地方写代码,代码就会变得更清晰.人们还说它更快,因为它不需要方法调用(尽管它可能永远不会对您的应用程序性能产生可测量的影响).

专业属性

更改属性的值将调用所有必需的KVO方法,以便在值更改时通知其他类.默认情况下,对属性的访问也是原子的(不能从多个线程访问),因此从多个线程读取和写入属性更安全(这并不意味着属性指向的对象是线程安全的,如果它是一个可变数组,然后多个线程仍然可以破坏非常糟糕的东西,它只会阻止两个线程将属性设置为不同的东西).

  • 关于使用变量,如果你的应用程序是游戏(刻度方法)或需要准确时间的东西(参见音乐级软件),额外的方法调用意味着吨. (2认同)

gsc*_*ler 5

正如您所建议的,您可以只使用@property@synthesize不声明 ivars。上面的问题是您@synthesize将属性名称映射到编译器生成的新 ivar。因此,出于所有意图和目的,您的类定义现在是:

@interface Test : NSObject {
int timesPlayed;
int highscore;
int _timesPlayed;
int _highscore;
}
...
@end
Run Code Online (Sandbox Code Playgroud)

timesPlayed如果您通过访问它,则将永远不会直接为 ivar 分配值,self.timesPlayed因为您没有修改正确的 ivar。

您有多种选择:

1 删除您在原始帖子中声明的两个 ivars,让@property/ @synthesizedynamic 二人组做他们的事情。

2 将您的两个 ivars 更改为以下划线“_”为前缀

3 将您的@synthesize语句更改为:

@implemenation Test
@synthesize timesPlayed;
@synthesize highscore;

...
Run Code Online (Sandbox Code Playgroud)