【问题标题】:What is the underlying mechanism for ivar synthesis in the modern Objective C runtime现代Objective C运行时中ivar综合的底层机制是什么
【发布时间】:2010-09-21 11:04:41
【问题描述】:

现代(64 位 OS X 和 iPhone OS)Objective C 运行时的特性之一是属性能够动态合成 ivars,而无需在类中显式声明它们:

@interface MyClass : NSObject {
//  NSString *name; unnecessary on modern runtimes
}

@property (retain) NSStrng *name;

@end

@implementation MyClass

@synthesize name;

@end

在我的很多代码中,我使用自定义 getter 实现来初始化属性:

- (NSString *) name {
  if (!name) {
    name = @"Louis";
  }

  return name;
}

上面的内容与合成的 ivar 不兼容,因为它需要访问一个未在标头中声明的 ivar。由于各种原因,我想更新我的一些个人框架以在现代运行时使用合成 ivars,为了实现该目标,需要修改上述代码以使用合成 ivars。

虽然 Objective C 2.0 文档声明现代运行时上的合成访问器将在首次使用时合成 ivar。它没有指定使用什么低级机制来执行此操作。是否由 class_getInstanceVariable() 完成,对 class_addIvar() 的限制是否松动,是否是目标 C 2.0 运行时中的未记录函数?虽然我可以为支持我的属性的数据实现自己的侧存储,但我更愿意使用合成访问器正在使用的机制。

【问题讨论】:

  • 如果你能得到答案,我会非常感动

标签: objective-c objective-c-runtime


【解决方案1】:

我刚才又去看了文档,我觉得你看错了。合成的 ivars 是在编译时创建的,而不是在运行时创建的。

根据Objective-C 2.0 documentation

取决于运行时的行为存在差异(另请参阅“运行时差异”):

对于旧版运行时,实例变量必须已经在 @interface 块中声明。如果存在与属性具有相同名称和兼容类型的实例变量,则使用它,否则会出现编译器错误。

对于现代运行时,实例变量是根据需要合成的。如果同名的实例变量已经存在,则使用它。

所以您需要做的就是声明您需要的实例变量,并且相同的代码将在两个运行时运行...

【讨论】:

  • 在阅读 gcc 的合成器代码后,这实际上是怎么回事。
  • Xcode 3.2 时代编译器(Clang/LLVM 和 GCC 4.2)的改进之一是您可以访问为支持合成变量而创建的 ivars,即使它们没有在类中声明,这让这一切都变得毫无意义。
【解决方案2】:

您在运行时使用NSKeyValueCoding Protocol 添加属性。

[myObject setValue:@"whatever" forKey:@"foo"];

【讨论】:

  • 这是不正确的。您可以使用键值编码设置值,但不能以这种方式添加属性。
  • 如果类实现了该协议,您绝对可以使用 NSKeyValueCoding 添加新值。但你是对的,这是对这个问题的错误答案,因为 ivars 是在编译时创建的,而不是使用 NSKeyValueCoding。
  • 重读答案。您不能通过键值编码添加属性
【解决方案3】:

您要查找的是@synthesized 名称,例如:

@synthesize name = _name;

...

- (NSString *) name {
    if (!name) {
        _name = @"Louis";
    }

    return _name;
}

【讨论】:

    猜你喜欢
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 1970-01-01
    • 2012-11-14
    • 2011-03-06
    • 1970-01-01
    • 2011-09-29
    相关资源
    最近更新 更多