RAC学习笔记之一:KVC(一)

摘要

RAC学习笔记之一:KVC(一)

博客

原帖收藏于IT老兵博客

前言

学习RAC,需要先去了解KVC和KVO,这里对KVC进行一下总结。

正文

KVC

参考苹果官网的介绍

You typically use accessor methods to gain access to an object’s properties. A get accessor (or getter) returns the value of a property. A set accessor (or setter) sets the value of a property. In Objective-C, you can also directly access a property’s underlying instance variable. Accessing an object property in any of these ways is straightforward, but requires calling on a property-specific method or variable name. As the list of properties grows or changes, so also must the code which accesses these properties. In contrast, a key-value coding compliant object provides a simple messaging interface that is consistent across all of its properties.


Key-value coding is a fundamental concept that underlies many other Cocoa technologies, such as key-value observing, Cocoa bindings, Core Data, and AppleScript-ability. Key-value coding can also help to simplify your code in some cases.

一言以蔽之,这一段的意思是编写传统的获取和设置属性的方法(getter和setter)会随着属性值的增加而变得越来越枯燥,所以OC提供了一种直接根据属性名设置值的方法,这种方法就叫做KVC,Key-value coding。

下面摘录一段李刚的《疯狂iOS》,这段例子讲的很清楚,所以摘录在下面:

5.5.1 简单的 KVC
最基本的 KVC 由 NSKeyValueCoding 协议提供支持,最基本的操作属性的两个方法如下。
setValue:属性值 forKey:属性名:为指定属性设置值。
valueForKey:属性名:获取指定属性的值。
例如,如下程序定义了 FKUser 类的接口部分。
程序清单: codes/05/5.5/FKUser. H

1
2
3
4
5
6
7
#import  <Foundation/ Foundation. H>
@interface FKUser: NSobject
//使用@property 定义 3 个 property
@property (nonatomic, copy) NSString* name;
@property (nonatomic, copy) NSString* pass;
@property (nonatomic, copy) NSDate* birth;
@end

上面程序定义了 FKUser 类使用@property 定义 3 个 property,接下来应该为该类定义实现部分,实现部分使用@synthesize 为这 3 个 property 合成 setter 和 getter 方法。类实现部分代码非常简单,故此处不再给出。
下面使用 KVC 来设置 FKUser 对象的属性,以及访问 FKUser 对象的属性。程序代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
程序清单: codes/05/5.5/FKUserTest.m

#import "FKUser. H"
int main (int argc,char★argv [])
{
@autoreleasepool {
//创建 FKUser 对象
FKUser* user = [[FKUser alloc] init];
// 使用 KVC 方式为 name 属性设置属性值
[user setValue: @“孙悟空”forKey: @"name"];
//使用 KVC 方式为 pass 属性设置属性值
[user setValue: @"1455" forKey: @"pass"];
//使用 KVC 方式为 birth 属性设置属性值
[user setValue: [[NSDate alloc] init] forKey: @"birth"];
//使用KVC 获取 FKUser 对象的属性
NSLog (@"user 的 name 为:%@“,【user valueForKey: @"name"]);
NSLog (@"user 的 pass 为:%@“,【user valueForKey: @"pass"]);
NSLog (@"user 的 birth 为:%@”,【user valueForKey: @"birth"]);

上面程序中前 3 行粗体字代码使用 KVC 方式为属性设置属性值,后 3 行粗体字代码使用 KVC 模式获取指定属性的值。
编译、运行上面的程序,看到如下输出:

1
2
3
user 的 name 为:孙悟空
user 的 pass 为:1455
user 的 birth 为:2013-04-08 16:55:49 +0000

在 KVC 编程方式中,无论调用 setValue: forKey 方法,还是调用 valueForKey:方法,都是通过 NSString 对象来指定被操作属性的,其中 forKey:标签用于传入属性名。
对于 setValue:属性值 forKey@”name“;代码,底层的执行机制如下。
(1) 程序优先考虑调用“setName:属性值;”代码通过 setter 方法完成设置。


(2) 如果该类没有 setName:方法,KVC 机制会搜索该类名为_ name 的成员变量,无论该成员变量是在类接口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条 KVC 代码底层实际上就是对 name 成员变量赋值。


(3) 如果该类既没有 setName:方法,也没有定义_ name 成员变量,KVC 机制会搜索该类名为 name 的成员变量,无论该成员变量是在类接口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条 KVC 代码底层实际就是对 name 成员变量赋值。


(4) 如果上面 3 条都没有找到,系统将会执行该对象的 setValue: forUndefinedKey:方法。
默认的 setValue: forUndefinedKey:方法实现就是引发一个异常,这个异常将会| 导致程序因为异常结束。


对于“valueforKey@”name”;,”代码,底层的执行机制如下。
(1) 程序优先考虑调用“name;”代码来获取该 getter 方法的返回值。


(2) 如果该类没有 name 方法,KVC 机制会搜索该类名为_ name 的成员变量,无论该成员变量是在类接口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条 KVC
代码底层实际就是返回_ name 成员变量的值。


(3) 如果该类既没有 name 方法,也没有定义_ name 成员变量,KVC 机制会搜索该类名为name 的成员变量,无论该成员变量是在类接口部分定义,还是在类实现部分定义,也无论用哪个访问控制符修饰,这条 KVC 代码底层实际就是返回 name 成员变量的值。


(4) 如果上面 3 条都没有找到,系统将会执行该对象的 valueforUndefinedKey:方法。

总结

KVC的内容有点多,一章总结不完,这篇文章基本都是摘录了,因为李刚的文章写得相当清楚,那就通过摘录来加深印象。

参考

https://developer.apple.com/documentation/foundation/object_runtime/nskeyvaluecoding?language=objc
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/index.html
https://www.objc.io/issues/7-foundation/key-value-coding-and-observing/