目标C中的关键值编码和关键值观察是什么?

有人能够简单地解释什么是Key-Value-CodingKey-Value-Observing ? 请不要提供指向Apple开发人员参考文档的链接。 我已经经历过他们。 我期待一个非常简单的解释。

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

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

这可能是一样的:

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

键值观察(KVO)允许您观察对属性或值的更改。

使用KVO观察一个物业,你可以用一个string来识别物业; 即使用KVC。 因此,可观察对象必须符合KVC。

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

键值编码只是简单地通过string访问对象的属性,而不是字面语法。

 // 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的强大之处在于你可以在运行时指定任意string(显然这也是非常危险的)。

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

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

一个很好的例子就是Mac上的NSTableView,你可以在每一个表格列上设置一个标识符,这个表格列对应于你应该显示的模型对象的属性,然后你的数据源只需要调用-valueForKey:/ – setValue:forKey:with列的标识符作为键和值自己显示/设置。 您只需将正确的列添加到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]; } 

这样做的好处是你可以在其他属性改变的时候被叫住。 请注意,对象必须做一些工作,以便发送这些通知,因此并非所有的属性都是可以键值观察的。 还要注意的是,如果两个相关的属性被一个接一个地改变,那么一些对象可能处于无效状态:在第一个属性被改变之后,你会得到通知,现在与第二个属性相矛盾,只有第二个属性被改变,重新通知。 因此,在第一次观察者callback期间,对象可能处于奇怪的状态,所以要小心如何对此作出反应。

为了使属性成为可观察的,当你定义它的时候使用默认的@synthesized实现,或者你自己定义它,执行如下的setter:

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

然后总是通过setter来改变它,不要直接改变_foo。 如果你有相互矛盾的相关属性,避免这种情况的一个好办法就是总是把它们成对地改变(然后你不能使用KVC)。 要做到这一点,执行一个组合的setter,如:

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

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

从这里开始。

键值编码是间接访问对象属性的一种机制,使用string来标识属性,而不是通过调用访问器方法或直接通过实例variables来访问它们。