【问题标题】:What is Key-Value-Coding and Key-Value-Observing in Objective C?Objective C 中的 Key-Value-Coding 和 Key-Value-Observing 是什么?
【发布时间】:2011-05-16 00:18:42
【问题描述】:

谁能简单解释一下Key-Value-CodingKey-Value-Observing是什么?请不要提供指向 Apple Developer 参考文档的链接。我已经通过了它们。我希望得到一个非常简单的解释。

【问题讨论】:

标签: objective-c


【解决方案1】:

键值编码 (KVC) 是指使用字符串访问属性或值。

id someValue = [myObject valueForKeyPath:@"foo.bar.baz"];

可能与以下内容相同:

id someValue = [[[myObject foo] bar] baz];

Key-Value-Observing (KVO) 允许您观察属性或值的变化。

要使用 KVO 观察属性,您可以使用字符串标识属性;即,使用 KVC。因此,可观察对象必须符合 KVC。

[myObject addObserver:self forKeyPath:@"foo.bar.baz" options:0 context:NULL];

【讨论】:

  • 这和上面的“darren”是一样的吗?哈哈
  • @Jacob Relkin Darrens 之一应该是darren *darrenB = &darrenA; :)
  • 不,但看起来我们都来自同一个城镇,同时回答同样的问题......几率是多少?
  • 如此很奇怪。并且具有大致相同数量的代表和徽章。嗯嗯嗯嗯......
  • 达伦,这个“addObserver”是做什么的?你能解释一下吗?
【解决方案2】:

键值编码只是通过字符串而不是文字语法访问对象的属性。

// Here is a new instance of an object
Foo *foo = [[Foo alloc] init];
// Accessing a property called someValue with literal syntax:
[foo someValue];
// Accessing the same property with dot notation
foo.someValue;
// Accessing the same property with Key-Value coding:
[foo valueForKey:@"someValue"];

KVC 的强大之处在于您可以在运行时指定任意字符串(显然这也可能非常危险)。

【讨论】:

  • 嗨,你能不能把最后一步充实一下——我还不了解 KVC 的“力量”。我知道我可以说 [carObject valueForKeyPath:@"changePriceToFree"] 但该属性 (changePriceToFree) 必须预先存在才能让我使用 KVC。那么为什么不直接调用该属性呢?我知道我可以在运行时改变我在代码中调用的键,但我仍然不知道如何在现实生活中应用这个事实。我认为这是 ios 开发者应该知道的核心话题。谢谢!
  • 这是一个出色的解释。但是,我也会回应 user798719 的问题,即为什么 KVC 如此强大,为什么要使用它而不是使用文字或点符号来调用属性?谢谢!
  • @user798719(和@daspianist),假设你有一个存储了Objective-C对象的数据库。您现在需要检索一个对象。无需手动获取每个字段并将其手动存储到新对象中(通过点或文字语法),您可以遍历数据库中的每个字段并在对象上调用 setValue:ForKey:。例如:您有一个对象“Person”,其属性为“name”和“bio”。您的数据库具有“名称”和“生物”字段。由于名称相同,您可以遍历数据库字段并在新的“Person”对象上调用 setValue:ForKey:(带有字段名称)。
【解决方案3】:

键值编码允许您在运行时使用字符串获取或更改对象的属性,而无需编写从一开始就编译为固定属性的代码:

NSNumber* foo = [myPopup valueForKey: @"selectedItemIndex"];
[myPopup setValue: @15 forKey: @"selectedItemIndex"];

一个很好的例子是 Mac 上的 NSTableView,您可以在每个表列上设置一个标识符,该标识符对应于它应该显示的模型对象的属性,然后您的数据源只需调用 -valueForKey:/-setValue: forKey:以列的标识符作为键,值几乎可以自行显示/设置。您只需将正确的列添加到 XIB 的表视图中。

后来添加了键值观察,并允许您注册以收到有关对另一个对象所做的更改的通知。您通过以下方式注册您的兴趣:

void*    gMyKVOContext = &gMyKVOContext; // global variable somewhere that guarantees us a unique address that doesn't collide with a subclass's registration for observing the same property

...

[interestingObject addObserver: interestedObject forKeyPath: @"interestingProperty" options: 0 context: gMyKVOContext];

每当更改该属性时,-observeValueForKeyPath:ofObject:change:context: 将在您指定为观察者的对象上调用。所以你可以这样实现:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if( context == gMyKVOContext && [keyPath isEqualToString: @"interestingProperty"] )
    {
        // Update UI that shows interestingProperty
    }
    else
        [super observeValueForKeyPath: keyPath ofObject: object change: change context: context];
}

这里的好处是,当其他属性发生更改时,您会被实时调用。请注意,对象必须做一些工作才能发送这些通知,因此并非所有属性都是 key-value-observable。另请注意,如果两个相关属性紧随其后发生更改,则某些对象可能处于无效状态:您在第一个属性更改后收到通知,现在与第二个属性相矛盾,然后只有第二个属性更改并且您重新通知。所以在第一次观察者回调期间,对象可能处于奇怪的状态,所以要小心你对此的反应。

要使属性可观察,请在定义它时使用默认的@synthesized 实现,或者如果您自己定义它,请像这样实现 setter:

-(void)  setFoo: (int)inFoo
{
    [self willChangeValueForKey: @"foo"];
    _foo = inFoo;
    [self didChangeValueForKey: @"foo"];
}

然后总是通过setter去改变它,不要直接改变_foo。如果您有可能像上面那样相互矛盾的相关属性,避免这种情况的一个好方法是始终成对更改它们(但此时您不能使用 KVC)。为此,请实现一个组合设置器,例如:

-(void) setFoo: (int)inFoo bar: (int)inBar
{
    [self willChangeValueForKey: @"foo"];
    [self willChangeValueForKey: @"bar"];
    _foo = inFoo;
    _bar = inBar;
    [self didChangeValueForKey: @"bar"];
    [self didChangeValueForKey: @"foo"];
}

这样,两个通知都会在属性处于正确状态时发送。

【讨论】:

    【解决方案4】:

    Start here.

    键值编码是一种机制 访问对象的属性 间接地,使用字符串来识别 属性,而不是通过 调用访问器方法或 通过直接访问它们 实例变量。

    【讨论】:

    • 来自原始问题“请不要提供指向 Apple Developer 参考文档的链接。”
    【解决方案5】:

    Objective-C 键值编码(KVC)与键值观察(KVO)

    [Swift KVC]

    KVC 允许您通过 String 访问属性,它为所有 NSObject 后继者启用。它为语言增添了活力。您可以将您的课程视为 Dictionary(Key-Value)。这是分配/读取/写入变量的替代/非直接解决方案

    [valueForKey vs valueForKeyPath]

    B *b = [a valueForKeyPath:@"b"];
    

    KVCKVO 使用,以及CoreData、Cocoa 绑定...

    KVO 允许您订阅更改的值。它适用于动态调度

    someClass.observe(\.v, options: .new) { (object, change) in
        //logic
    }
    

    [KVO example]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-18
      • 1970-01-01
      • 2013-06-24
      • 1970-01-01
      相关资源
      最近更新 更多