【问题标题】:What's the difference between KVC and Properties?KVC 和属性有什么区别?
【发布时间】:2012-01-01 17:53:30
【问题描述】:

所以,我已经阅读了有关注释的文档

Objective-C 2.0 的点语法和键值编码是正交技术。无论是否使用点语法都可以使用键值编码,无论是否使用 KVC,都可以使用点语法。不过,两者都使用“点语法”。在键值编码的情况下,语法用于分隔键路径中的元素。请务必记住,当您使用点语法访问属性时,您会调用接收者的标准访问器方法。

然后它提供了一个示例,据说可以显示两者之间的差异。但是,我仍然不明白,KVC 和属性访问器方法有什么区别?他们不一样吗?以及如何区分调用 setValue:forKeyPath: 的点和简单的访问器?

【问题讨论】:

    标签: objective-c cocoa key-value-coding


    【解决方案1】:

    键值编码允许您使用属性的字符串名称通过代码设置和获取属性的值。例如,如果我有一个 NSString 类型的名为 foo 的属性:

    [self setValue:@"mystring" forKey:@"foo"];
    
    // read the value by key
    NSString *s =  [self valueForKey:@"foo"];
    

    点语法是编译语法糖。作为个人喜好(有些人不同意 - 很好)我不使用点语法,但我仍然使用 KVC:

    [myObj setFoo: @"someString"]
    

    等于:

    myObj.foo = @"someString";
    

    它们是正交的、不同的概念,但都涉及您如何与属性交互

    最后,您提到了属性语法。另一个正交概念,但与处理属性有关。

    对于objective-c,约定很重要。跟着他们。属性是 get 和 set[Name] 的属性名称:

    - (NSString*)foo
    {
        return _foo;  // defined as (NSString*)_foo in header
    }
    
    - (void) setFoo: (NSString*)foo
    {
        if (foo == _foo)
            return;
    
        NSString* curr = _foo;
    
        _foo = [foo retain];
        [curr release];    
    }
    

    现在,谁想每次都写这样的东西。所以,输入@property 语法:

    在标题中:

    @property (retain) NSString *foo;
    

    然后在.m:

    @synthesize foo;
    

    这相当于手写的属性访问器。它是一种编译器语法糖,可以根据您对属性的属性进行扩展。

    文档:

    http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueCoding/Articles/KeyValueCoding.html

    http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html

    【讨论】:

      【解决方案2】:

      但是,我还是不明白,KVC 和属性访问器方法有什么区别?

      KVC 是一种调用属性访问器方法或以其他方式访问属性的方法。

      “否则访问”是什么意思?对于 KVC 目的,没有访问器方法的实例变量算作非正式属性。如果找不到匹配的访问器对,它将直接获取或设置实例变量的值。 (是的,这不值得在现代代码中使用。始终为您打算在其他地方访问的任何内容声明 @property,并且相反,不要使用 KVC 访问任何不是公共属性的内容。)

      如果存在,KVC 将调用属性访问器方法(KVC 和每个理智的程序员都喜欢直接访问 ivar)。访问器可以像合成访问器一样获取或设置实例变量,也可以访问其他存储。

      访问器是实现,属性是接口,KVC是使用它们的一种方式。

      我如何区分调用 setValue:forKeyPath: 的点和简单的访问器?

      键路径是字符串,而属性访问表达式是表达式。编译器评估属性访问表达式并将其转换为一个或多个 Objective-C 消息,而关键路径由 KVC 在运行时评估。

      所以,当你使用关键路径时:

      [someObject setValue:theValue forKeyPath:@"foo.bar.baz"];
      

      您知道它是一个键路径,因为 (1) 它是一个字符串,如本例中的字符串文字语法 @"…" 所示,并且 (2) 您将键路径字符串传递给 setValue:forKeyPath:它来评估。

      使用密钥路径是使用 KVC 访问命名属性。它将代表您发送任何相关的访问者消息。

      当您使用属性访问表达式时:

      someObject.foo.bar.baz = theValue;
      

      您知道这是一个属性访问表达式,因为您没有用字符串标识属性。您正在自己的代码中访问它们(发送访问者消息)。

      没有太多理由以任何形式使用 KVC;当您在作者身份/编译时知道该属性时,最好声明 @property 并自己访问该属性,无论是使用属性访问表达式还是消息表达式 ([[[someObject foo] bar] setBaz:theValue])。使用 KVC 的时间是在运行时才知道要访问什么属性,这种情况非常罕见。它主要是 KVO、Cocoa Bindings、Core Animation 的部分等背后的构建块技术。

      大多数情况下,您只想自己访问属性。

      【讨论】:

      • “使用 KVC 的时间是当您在运行时才知道要访问什么属性” 从您的答案中我一直在寻找,谢谢。
      • 这对我真的很有帮助。我的想法是使用 KVC 的时间是当您不知道要访问什么属性时,直到运行时,这可能是原因,但我不确定。你让我对自己的想法充满信心。
      • Peter you state ",相反,不要使用 KVC 访问任何不是公共财产的东西。"我刚刚发现,如果一个属性被声明为只读,然后在实现中重新声明为读写,那么 KVC 将无耻地写入该属性。有没有办法阻止这个?我试过 (BOOL) accessInstanceVariablesDirectly { return NO;} 但这并不能阻止 KVC 写入属性。
      • @WS:不。 KVC 早于正式属性,并且没有 readonly 与 readwrite 的概念,更不用说公开声明为 X 和私有声明为 Y。它只关心是否有 getter 或 getter 和 setter。如果属性是readwrite,即使只是私有的,那么这个setter也存在——而Objective-C中的方法没有公有/私有的区别,所以如果它存在,它对所有人都存在。
      猜你喜欢
      • 2011-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      • 2016-04-29
      • 2018-04-28
      相关资源
      最近更新 更多