kvc机制,kvo与kvc
KVO/KVC摘要
以下是网上文章的汇总,方便查看。
在网上阅读别人的文章来了解KVC和KVO。有一个kvo-kvc的例子,就是改变数组的内容(插入和删除),同步改变tableview中的内容。运行完代码,想在添加和修改数组的时候改变tableview的内容,但是一直调用不了observation函数。后来查了一些资料。原来数组的kvc是有固定格式的函数名。将修改后的项目放入资源中。供大家下载。以下是复制的资料。
一、KVC和KVO的概念1 KVC:NSKeyValueCoding的简称,是一种可以通过字符串的名称(key)直接访问类属性的机制,而不是通过被调用的Setter和Getter方法。
2 KVO:NSKeyValueObserving的缩写,这种机制允许指定的对象在其属性被修改时接收通知。
二。KVC简介。概观
KVC是KeyValue Coding的缩写,这是一种可以通过字符串(键)的名称直接访问类属性的机制。而不是调用Setter和Getter方法。
KVC是使用KVO、核心数据、协同绑定和AppleScript(Mac支持)时的关键技术。
2.如何使用KVC
密钥方法在:NSKeyValueCodingprotocol中定义
KVC支持类对象和内置的基本数据类型。
获得价值
ValueForKey:传入NSString属性的名称。
ValueForKeyPath:以xx.xx的形式传递给NSString属性的路径
valueForUndefinedKey的默认实现是引发异常。您可以为错误处理重写该函数。
修改值
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
SetNilValueForKey:在非类对象属性上设置nil时,默认情况下调用它并抛出异常。
一对多关系成员
MutableArrayValueForKey:有序的一对多关系成员NSArray
MutableSetValueForKey:无序的一对多关系的成员NSSet
3.KVC实施细则
搜索Setter和Getter方法
这部分比较重要,可以让你知道调用KVC后,如何获取和设置类成员的值。
搜索简单成员
例如基本类型成员,单对象类型成员:NSInteger,NSString*成员。
A.setvalue:forge的搜索方法:
首先搜索set Key: method。
如果用@property处理成员,@synthsize,因为@synthsize告诉编译器自动生成set Key形式的setter方法:这种情况下会直接搜索。
注意:这里的键指的是成员名,首字母大写。下同。
上面的setter方法没有找到,如果类方法AccessInstanceVariableSDIrectly直接返回YES(注意:这是在NSKeyValueCodingCatogery中实现的类方法,默认实现是返回YES)。
然后按照_键,_是键,键,是键的顺序搜索成员名。
如果找到设置成员的值,如果setValue:forUndefinedKey:未被调用。
B.valueForKey:搜索方法:
1.首先按照get Key,Key,is Key的顺序找到getter方法,找到直接调用。如果是bool、int等内置值类型,会做NSNumber转换。
2.找不到上面的getter。查找countOf Key、objectIn Key AtIndex:和Key AtIndexes格式的方法。
如果找到countOf键和另外两个方法之一,将返回一个可以响应NSArray所有方法的集合代理对象。发送到此代理集合(collectionproxy对象)的NSArray消息方法将以几种方法组合的形式调用:countOf Key、objectIn Key AtIndex:和Key AtIndexes。还有一个可选的get Key :range:方法。
3.如果还没找到,那么找到countOf Key、enumeratorOf Key、memberOf Key的格式的方法:
如果这三个方法都找到了,将返回一个可以响应NSSet所有方法的集合代理对象。发送到此代理集合(集合代理对象)的NSSet消息方法将以countOf Key、enumeratorOf Key和memberOf Key的组合形式调用:
4.还是没有找到,那么如果类方法accessinstancevaluablesdirectly返回YES,那么直接按照_ key,_is key,Key,is Key的顺序搜索成员名。
5.如果再次找不到,则调用valueForUndefinedKey:
查找有序集成员,如NSMutableArray。
MutableArrayValueForKey:搜索方法如下:
1.在索引:处的关键字中搜索插入对象的格式,从索引:处的关键字中删除对象,或在索引:处插入关键字,在索引:处删除关键字。
如果找到了至少一个insert方法和至少一个remove方法,还会返回一个可以响应NSMutableArray的所有方法的代理集。然后以insertObject:in Key AtIndex:removeObjectFrom Key AtIndex:insert Key :atIndexes,remove Key AtIndexes:有两个可选接口:用对象替换索引处键中的对象,用键替换索引处的键。
2.否则,搜索set Key:格式的方法,如果找到,那么发送到代理集合的NSMutableArray最终将调用set Key:方法。
也就是说,mutableArrayValueForKey取出的代理集合被修改后,用set Key重新赋值:这样效率会低很多,建议实现上面的方法。
3.否则,如果类方法AccessInstanceVariableSdirectly返回YES,则直接按照_ key,key的顺序搜索成员名。如果找到了,那么发送的NSMutableArray消息方法直接传递给这个成员进行处理。
4.如果再找不到,调用setValue:forUndefinedKey:
搜索无序集合成员,如NSSet。
MutableSetValueForKey:搜索方法如下:
1.以add Key Object:removeyobject:或add Key:removeykey:的格式搜索方法,如果找到至少一个insert方法和至少一个remove方法,则返回一组可以响应NSMutableSet的所有方法的代理。然后以add Key Object:removeyobject:add Key:removeykey:的组合形式调用发送到这个代理集的NSMutableSet消息方法。还有两个可选接口:相交关键点和设置关键点:
2.如果reciever是ManagedObejct,则搜索将不会继续。
3.否则,在set Key: format中搜索方法。如果找到了,那么发送到代理集合的NSMutableSet将最终调用set Key:方法。也就是说,mutableSetValueForKey检索到的代理集被修改后,用set Key重新赋值:这样效率会低很多,建议实现上面的方法。
4.否则,如果类方法AccessInstanceVariableSdirectly返回YES,则直接按照_ key,key的顺序搜索成员名。如果找到了,那么发送的NSMutableSet消息方法就直接传递给这个成员进行处理。
5.如果再找不到,调用setValue:forUndefinedKey:
KVC还提供以下功能
检查该值的正确性
KVC提供了属性值确认的API,可以用来检查set的值是否正确,替换不正确的值,或者拒绝设置新值并返回错误原因。
实现验证方法
采用以下格式:验证密钥:错误:
比如:
-(BOOL)validate name:(id *)io value error:(NSError * *)out error
{
//Thenamemustnotbenil和mustbeatleatsttwocharacters long。
if((* ioValue==nil) ([(ns string *)* ioValuelength]2]){
if(outError!=NULL){
ns string * errorString=NSLocalizedStringFromTable(
@Person snamemustbeatleatsttwocharacters long ,@ Person ,
@ validation:tooshortname error));
NSDictionary*userInfoDict=
[NSDictionarydictionaryWithObject:错误字符串
forKey:NSLocalizedDescriptionKey];
* out ERROR=[[[NSErroralloc]initWithDomain:PERSON _ ERROR _ DOMAIN
代码:人员_无效_姓名_代码
userInfo:userInfoDict]auto release];
}
returnNO
}
returnYES
}
调用验证方法:
Validate value: forge key: error:默认实现会搜索validate Key :error:格式的验证方法,找到就调用。如果没有找到,默认返回YES。
注意内存管理问题。
集合运算
set操作是通过将参数传递给valueForKeyPath:来使用的,必须在set上使用(如:array),否则会发生运行时错误。其格式如下:
Leftpath部分:需要操作对象路径。
Collectionoperator部分:使用@符号来确定所使用的集合操作。
Rightpath部分:需要设置的属性。
1.数据操作
@avg:平均值
@count:总数
@max: max
@min:最小值
@sum: total
确保操作的属性是数值类型,否则运行时会出错。
2.目标操作
在数组的情况下
@ distinctUnionOfObjects:返回指定属性的已消除重复值的数组。
@ UnionofoObjects:返回指定属性的值的数组,没有重复。
属性的值不能为空,否则将生成异常。
3.数组操作
阵列的阵列盒
@distinctUnionOfArrays:返回指定属性的已消除重复值的数组。
@unionOfArrays:返回指定属性的值的数组,没有重复。
@distinctUnionOfSets:同上,只是返回值是NSSet。
3.KVC实施情况分析
KVC使用isa-swizzing技术。Isa-swizzling是类型混合指针机制。KVC主要通过isa- swizzling实现内部搜索和定位。Isa指针,顾名思义,(意思是一种),指向维护分布表对象的类。分布表实际上包含了指向实现类中的方法的指针,以及其他数据。
例如,下面一行KVC代码:
[site setValue:@ sitename for key:@ name ];
将被编译器处理成:
SEL=SEL _ get _ uid( setValue:forKey:);
IMP method=objc _ msg _ lookup(site-isa,sel);
方法(site,sel,@sitename ,@ name );
首先,介绍两个基本概念:
(1)SEL数据类型:它是编译器运行Objective-C中方法的环境参数。
(2)IMP数据类型:实际上是编译器内部实现时的函数指针。Objective-C编译器在处理一个方法的实现时,会指向一个IMP对象,这个IMP对象是用C语言表示的类型(其实Objective-C编译器处理的时候,基本都是用C语言)。
请参考文章:《Objective-C如何避免动态绑定,而获得方法地址》:http://www.cocoadev.cn/Objective-C/Get-method-address.asp,了解如何找到实现该函数的指针。
KVC的内部实现非常清晰:当一个对象调用setValue时,(1)首先根据方法名找到运行方法所需的环境参数。(2)他会从他的isa指针结合环境参数找到实现接口的具体方法。(3)找出直接实现的具体方法。
四。KVO简介
Kvo是可可的一个重要机制。它提供了一种观察属性变化的方法,这大大简化了代码。这种观察-被观察模型适用于这样的情况,例如,根据A(数据类)的一个属性值的变化,B(视图类)中的一个属性也随之变化。对于崇尚MVC的可可来说,kvo被广泛使用。(这种机制听起来像通知,但是通知需要一个发送通知的对象(通常是notificationCenter)来通知观察者。并且kvo被直接通知给被观察对象。)
应用kvo时,通常遵循以下流程:
1注册:
-(void)add observer:(ns object *)a observer for key path:(ns string *)key path选项:(NSKeyValueObservingOptions)选项上下文:(void*)上下文
KeyPath是要观察的属性值,options给你观察键值变化的选择,context方便传递你需要的数据(注意这是void类型)。
2.实现变化的方法:
-(void)observeValueForKeyPath:(ns string *)对象的密钥路径:(id)对象
change:(NSDictionary*)更改上下文:(void*)上下文
Change存储一些改变的数据,比如改变前后的数据;如果注册时上下文不为空,则可以在此处接收上下文。
这不是很简单吗?kvo的逻辑非常清晰,实现步骤也很简单。
说到这里,大家都跃跃欲试。然而,在此之前,我们需要了解KVC机制。其实了解kvo的逻辑只是为了帮助你理解。你真正要掌握的不是kvo的实现步骤是什么,而是KVC,因为只有符合KVC标准的对象才能使用kvo(强烈建议想使用kvo的人先了解KVC)。
KVC是一种间接访问对象(由字符串表示)属性的机制,而不是直接调用对象的访问器方法或直接访问成员对象。
键是确定对象值的字符串。它通常与访问器方法或变量同名,并且必须以小写字母开头。路径是由“.”分隔的键因为属性值也可以包含属性。例如,我们可以有一个类似person的键或类似key.gender的键路径。
获取属性值时,可以使用valueForKey:的方法将属性值设置为setValue:forKey:同时,KVC还定义了valueForUndefinedKey:对于未定义的属性值,你可以重载它以获得你想要的实现(补充,KVC定义包含在NSKeyValueCoding的非正式协议中)。
属性是在O-C 2.0中引入的,我们也可以通过。接线员。让我们直接看一个例子:
@ property NSInteger number
instance . number=3;
[实例集值:[ns number number within integer:3]forKey:@ number ];
请注意,KVC中的所有值都必须是对象。
上面描述了如何通过KVC获取/设置属性,下面将说明实现KVC的访问器方法。苹果给出的约定通常是:
- key:和setKey:(命名约定和setter/getter命名相同)。对于未定义的属性,可以使用setnilvaluework:
至此,你应该已经掌握了KVC的基本概念。之所以说基本,是因为kvc只涉及单值情况,所以也可以应用于多对多关系,这里就不说了,留给大家自学的空间。
接下来,我们将以集合为例来练习我们已经掌握的KVC。
选择array,因为在ios中,经常使用array作为tableview的数据源,有这样一种情况:
假设我们有n条数据,经过一些运算,在原始数据之后又多了两条记录;或者更新和替换n中的一些数据.除了使用KVC,我们还可以使用reloadData方法或reloadRowsAtIndexPaths。前者的缺点是n很大的话就很大。想象一下,你只添加了几条数据,却要重新加载前面的N条数据。后一种方法的缺点是代码是多余的。你必须一次计算每个indexPath,然后重新加载它,你必须提前考虑在什么情况下数据会被更新。
如果使用KVC/kvo,这种麻烦就迎刃而解了,你不用担心增加或更新了多少条数据。
下面以添加数据为例来说明要实现的方法:
实现insert object:inkyatindex:或insertKey:atIndexes。同时,在kvo中,我们可以通过变化字典了解到发生了什么样的变化,从而进行相应的处理。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。