【问题标题】:Objective-C: What is a lazy class?Objective-C:什么是惰性类?
【发布时间】:2013-03-09 20:38:52
【问题描述】:

查看 Objective-C 运行时库源代码,特别是在 objc-runtime-new.mm,我看到一些函数甚至 cmets 引用了惰性和非惰性类。似乎没有 +load 方法的类被称为惰性类,但我不确定这一点,而且很可能这是不对的。在 Google 上搜索后,我没有找到任何关于 Objective-C 上惰性类的信息。

那么,什么是 Objective-C 中的惰性类? Obj-C 有这个功能吗?它是否与类的实现中存在+load 方法有关?在上面链接的文件中,运行时系统调用一个名为 _getObjc2NonlazyClassList 的函数,以便从图像中获取非惰性类的列表。为什么没有_getObjc2LazyClassList 函数呢?

【问题讨论】:

  • 可能是从插件加载的类。也许检查有关插件/dyld/动态加载代码的文档
  • 你确定这意味着该类是懒惰的,而不仅仅是列表?
  • 我同意@JoshCaswell,因为稍后在运行时源代码中会引用延迟加载类。它几乎可以肯定是指列表,而不是“懒惰”的类。
  • @JoshCaswell @lxt 我还认为这是一个应该稍后加载的类列表,我不确定。但是在代码的某个点上,我发现了注释“// 实现非惰性类(用于 +load 方法和静态实例)”。在此评论之后,有一个对 _getObjc2NonlazyClassList 的调用,它似乎得到了一个惰性类列表(我还不确定),而不是一个惰性类列表。

标签: objective-c lazy-evaluation objective-c-runtime


【解决方案1】:

我找到了答案:这完全取决于一个类是否实现了 +load 方法。

在给定图像文件中实现的所有类在存储在"__DATA, __objc_classlist, regular, no_dead_strip" 二进制部分的列表中都有引用。此列表允许运行时系统跟踪存储在此类文件中的所有类。但是,并不是所有的类都需要在程序启动时实现。这就是为什么当一个类实现+load 方法时,它在"__DATA, __objc_nlclslist, regular, no_dead_strip" 部分中存储的列表中也有一个引用。

所以,_getObjc2NonlazyClassList 检索实现了+load 方法并且所谓的非惰性类的列表。 _getObjc2ClassList 检索图像文件中所有类的列表,包括没有 +load 方法的类(称为惰性)和非惰性类。非惰性类必须在程序启动时实现。另一方面,惰性类不需要立即实现。例如,这可能会延迟到班级第一次收到消息(这就是他们被认为是“懒惰”的原因)。

顺便说一下,类别也是如此。

【讨论】:

  • 请注意,对于类别,如果这些类别在外部库中,则必须使用 all_load 链接器标志。
  • 这可能几乎是正确的,但我见过包含 __objc_nlclslist 但不包含 __objc_classlist 部分的 MachO 图像。
【解决方案2】:

“懒惰”用于两种不同的上下文。

第一个,当批评一个类设计时,认为一个类是无效的——它没有做足够的事情来证明它的存在。人们也称这种类为“薄”。 这可能不是你的意思。

第二,惰性求值惰性实例化意味着类只在实际需要时才执行评估属性或初始化自身的工作。

例如,假设我们有一个创建 Employee 对象的类。

 @implementation Employee
 - (id) initWithID: (IdentificationCode*) ident
 {
    self =[super init]
    if (self) {
         _records=[self retrieveEmployeeRecordsFor: ident];
         _identification=ident;
         }
    return self;
}

这很好,但是从数据库中检索所有记录可能会很慢。有时我们不需要做这项工作。例如:

- (BOOL) isFounder
{
     if (indent.number<10) return YES;
     return NO;
}

如果我们实例化一个 Employee 只是为了确定他们是否是 Founder,我们根本不需要查找他们的记录!

 .....
 if ([thisEmployee isFounder]) {
      [self sendCandyTo: thisEmployee.identification];
      }

另一方面,有时我们需要它们:

- (NSArray*) payments
{
    return [self.records retrievePayStubs];
    }

所以,如果我们构建一个 Employee 只是为了调用 isFounder,我们会浪费数据库查找。但我们不能跳过它,因为payments 需要它。

我们所做的是从构造函数中取出数据库查找并将其放入load 方法中。

- (void) load
{
    if (records) return;
    self.records=[self retrieveEmployeeRecordsFor: ident];
}

- (NSArray*) payments
{
    [self load];
    return [self.records retrievePayStubs];
    }

现在,我们只在实际需要员工记录时才加载它们。如果它们已经被加载,我们不会做任何额外的工作(除了一个方法调用)。如果我们从不需要付款记录,那么我们根本不需要做这项工作。

这个类只在它必须的时候工作——并且等到最后一分钟才能完成工作。这是“懒惰”!

【讨论】:

  • 感谢您的回答,马克。这就是我的想象。因此,一个类因其行为而被视为lazy。但是有些事情仍然困扰着我:_getObjc2NonlazyClassList 函数的存在似乎加载了在图像文件中存储为非惰性的类。这就像有一个方面使一个类在编译时非惰性。或者可能只是命名法:从图像文件加载的所有类都被认为是非惰性的......
猜你喜欢
  • 2014-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-27
  • 1970-01-01
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多