【问题标题】:self.instance_var performance hit?self.instance_var 性能下降?
【发布时间】:2010-02-20 16:50:53
【问题描述】:

让 mFoo 是一个实例变量,它是一个已合成的属性,因此它具有默认的 setter 和 getter。我想知道是否需要关注使用的性能影响 self.mFoo vs.mFoo如果 mFoo 在逻辑语句中被重复访问。

在我看来,如果绝对确定一个方法没有声明局部变量 mFoo,并且在一个方法中与 mFoo 进行多次逻辑比较,并且该方法被调用了很多次,那是有道理的不是通过它的访问器方法访问mFoo,而是直接访问。

例如:

NSMutableArray *mFoo;
@property(nonatomic, retain) NSMutableArray *mFoo;
@synthesize mFoo;

-(void)someMethod {
    Bar* b;
    for (int i=0; i<10000; i++) {
        b = [self.mFoo objectAtIndex:i];   // <<<<<<<<<<<<<<<<
        if (b.something == 123) { // do something };
    }
 }

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    在我看来,如果一个人绝对确定一个方法确实 没有局部变量 mFoo 声明,一个正在做几个 与 mFoo 的逻辑比较 方法,该方法称为 很多,不访问是有道理的 mFoo 通过它的访问器方法但是 直接。

    始终使用访问器。 总是。永远不要通过将对象视为结构来直接获取值。这样做会破坏封装,等等,等等,等等……

    (请记住,self.mfoo 与以下讨论中的[self mfoo]完全是同义词)。

    现在,在这种情况下,您明显的优化是将self.mfoo 移出循环。按照 Mage 先生的建议,使用 for(Bar *b in self.mfoo) 语法。

    然而,真正的问题是 您是否测量了应用程序的性能并确定 那个 特定的方法调用实际上导致了任何重大开销?

    如果是这样,请优化。不过,最有可能的是,在宏伟的计划中没有可衡量的开销。

    【讨论】:

    • @bbum “永远不要直接获取值......”即使在课堂上,你也严格遵守这一点吗?如果类具有与之关联的属性,您是否永远不会让类获得 它自己的 ivar 值?
    • 一般来说是的。如果有键值观察在起作用,那么通过 setter/getter 将触发观察。
    • @Apple 请使用 self.在您的示例代码和 Xcode 模板中。从 Xcode 模板创建的项目中:[window addSubview:[navigationController view]]; [窗口 makeKeyAndVisible];
    【解决方案2】:

    如果您从另一个类访问属性,则应始终使用访问器方法或点表示法。这只是基本的 OO 卫生。万一您发现这会导致循环中的瓶颈或其他情况,您可以考虑一些量身定制的解决方案。

    如果您从类中的 访问变量,我认为直接访问ivar 而不是通过属性如果您正在获取值 是可以的。但是,如果您要设置该值,则应始终使用该属性,这既是为了避免内存泄漏,也是因为 setter 可能具有应该执行的逻辑。

    所以:

    CGSize sz = [self size]; //ok
    CGSize sz = self.size; //ok
    CGSize sz = _size; //ok, but be careful
    
    [self setSize:sz]; //ok
    self.size = sz, //ok
    _size = sz; // DON'T EVER DO THIS!
    

    但是,如果您的 ivar 甚至没有与之关联的属性,则无需说直接访问它(您没有太多选择...)。就个人而言,我通常为所有 ivars 声明属性,除了一些标志或非对象类型的计数器,但很多人不这样做。

    【讨论】:

      【解决方案3】:

      对于self.mFoo 的每次访问,如果启用了快速的Objective C 消息分发,则必须调用大约一个C 函数(除非编译器优化了该调用)。因此,大多数情况下对性能的影响不会很明显。在您提到的示例中,您应该使用快速枚举,例如

      for (Bar *b in self.mFoo) {
          // do whatever you wish to here
      }
      

      ,这将导致 self.mFoo 仅被访问一次并且通常更快(例如,如果您的数组确实是一个列表)。

      【讨论】:

      • 提前编译器无法优化它。由于消息分发和自省在 Objective C 中是如何工作的,实际上不可能知道内联方法是否安全,除非编译器有关于所有链接单元的完整信息(即使这样也可能很困难)。因为编译器从来没有这些信息(Mac OS X 支持可加载模块,而且我们大多数人都没有 Foundation 的源代码)。如果您在 JIT 环境中使用 ObjC,将来可能会进行某种单态调度内联。
      • for( ... in ...) 是一个很好的建议。但是,在这种情况下,没有“启用或禁用”objc 消息调度。编译器方面也没有任何优化机会。
      • 路易斯:你说得对,我没想到。 bbum:有一个快速的Objective C 消息调度选项,可以使这些调用非常快。但你是对的,消息总是会被发送的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-19
      • 2014-02-18
      • 2013-12-24
      • 2013-11-14
      相关资源
      最近更新 更多