使用self.fooBar和fooBar,性能是否有差异?

3
注意:我很清楚什么是属性。这个问题是关于性能的。
对于读取操作使用self.fooBar,我觉得这是浪费时间。这会导致不必要的Objective-C消息传递。getter通常只是简单地传递ivar,所以只要可以确定不会编写合理的getter方法,那么绕过这个重量级的东西是完全可以的。
Objective-C消息传递比直接调用慢大约20倍。因此,如果有一些高性能、高频率的代码正在使用数百个属性,也许避免不必要的Objective-C消息传递确实会有很大帮助?
还是说我在浪费时间思考这个问题?
6个回答

8
这种过早的优化应该推迟到你实际上注意到或测量(使用Instruments.app)真正存在问题的时候。

好的观点...我只能估计,但是像这样的几千个不必要的属性调用,而iPhone是一个缓慢的设备。 - dontWatchMyProfile

2

使用属性getter比直接访问要慢得多。属性getter在self类(和类别)以外的封装中很有用,但是我认为除非你已经将getter重写为其他内容,否则使用self.ivar getter没有任何好处。

(而且你为什么要首先使用self.ivar?)

唯一的情况是self.ivarself->ivar不同的情况:

  1. The property is atomic, so self.ivar will be similar to

    spin_lock(&ivar_lock);
    id retval = [ivar retain];
    spin_unlock(&ivar_lock);
    return [retval autorelease];
    

    for an id property, and

    spin_lock(&ivar_lock);
    spin_lock(&destination_lock);
    memcpy(&destination, &ivar, sizeof(ivar));
    spin_unlock(&ivar_lock);
    spin_unlock(&destination_lock);
    

    for a struct. There is no difference between the two when the property is nonatomic.

  2. When the class is not final. A category of the class or a subclass can override the property getter to something else. But I think overriding a concrete property is not a good style.

就像其他人所说的那样,除非您已经测试了getter是一个热点,否则将其改回直接ivar访问不会有太大帮助。


1
如果你不使用 self.ivar 来改变属性,其他观察它的键值对象将不会被通知到变化。此外,在非 GC 多线程环境中,直接访问 ivars 是不安全的(读或写)。 - JeremyP
1
@JeremyP:OP要求一个getter。你可以使用KVO观察变化,但那是用于setter的。 - kennytm
1
有时候使用getter获取内部信息是有意义的。例如:当访问ivar时,你想要发生某些事情。比如设置一个对象或者某些必须存在但现在不存在的东西。但在99%的情况下,getter是没有意义的。 - dontWatchMyProfile
1
线程安全的注释甚至适用于获取实例变量。此外,子类可能已经重写了getter方法。 - JeremyP
@Jeremy:没错。已更新以包含这些信息。 - kennytm

2

不冒犯,但你可能在浪费时间思考这个问题。除非你的代码每秒访问该属性数千次,否则你不会看到任何性能差异。


2
这两者并不完全可互换(尽管有时可以)。当你需要访问 ivar 时,请直接访问它;当你需要使用 accessor 方法时,请使用它。这可能取决于类层次结构、类的实现、代码是否线程安全等等,这些都是你自己要考虑的事情,如果是你的代码的话。也许有人想要子类化这个类,并编写一个自定义的 -foobar 实现,它总是返回 @"BOO",但他们发现超类方法 -printFooBar 现在打印出变量 foobar 的值,而不是从 self.foobar 返回的值。
调用 accessor 方法比直接使用变量具有更多的开销,但还有更多的事情需要考虑,而不仅仅是性能。就我个人而言,我觉得“始终使用 accessor 方法”和“永远不使用 accessor 方法”这两种立场同样荒谬 - 显然都是荒谬的。

1
有些人可能不同意,但我碰巧喜欢直接访问ivar并尽可能绕过整个消息传递的过程。我认为这样可以更清晰地表达我的意图,因为如果我需要调用getter(用于内存管理或类似操作),那么我会这样做。

在某种程度上我不同意。如果您的ivar支持一个属性,除非性能真的是一个问题或者在init/dealloc中使用,否则应始终使用访问器。这是因为直接访问ivar会绕过KVO机制,并且不是线程安全的。诚然,如果属性声明为nonatomic,那么它也不是线程安全的。 - JeremyP
我在某种程度上不同意这个说法。不使用标准的getter方法并不会绕过任何KVO机制,而使用原子属性也不能使您的应用程序“线程安全”。 - hooleyhoop
@mustISignUp:不,即使访问ivar以进行读取,在没有原子getter的情况下也不是线程安全的。 - JeremyP
1
我知道。我的意思是,使用原子getter并不能给你线程安全性。你需要一个比原子锁定变量访问更好的方案。 - hooleyhoop

0

它的效率略微降低了一点,但通常你仍然不应该将对象状态公开。虽然在大多数面向对象语言中,公共成员被认为是不好的,但在Objective-C中实际上有一个实用的原因:框架使用您的“getter”和“setter”方法来使某些事情自动化,例如内存管理和KVO通知。对于从多个地方访问的ivars,每个客户端代码都需要完全理解访问器方法承担的所有责任,并以完全相同的方式执行这些职责。

所以并不是“绝对不要访问自己的ivars”,而是要确保您充分了解在特定情况下它所涉及的内容。


没有太大的区别。KVO和Core Data仍然依赖于访问器方法中的行为,每一段代码仍然有责任处理原始方法中的事情,无论这段代码是在同一个类中还是在不同的类中。 - Chuck
在内部使用ivar访问与@property / KVC / KVO / Core Data并不矛盾。(顺便说一句,我没有给你投反对票。) - kennytm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接