新浦京81707con > 功能介绍 > KVC访问器实现详细,KVC的原理实现

原标题:KVC访问器实现详细,KVC的原理实现

浏览次数:165 时间:2020-03-29

本文翻译自苹果文书档案Accessor Search Implementation Details及措施的注脚。翻译的不允许则之处还请多多包含指正,谢谢~

一、什么是KVC

法定文书档案:

KVC(Key-Value Coding卡塔尔是Objective-C提供的一种采纳字符串来间接待上访问对象属性的一种体制,它是经过访谈器去拜会对象属性的另一个可选方案。非正式磋商NSKeyValueCoding对其接口进行了概念,NSObject中提供了接口的暗中同意达成。

1、介绍:

KVC键值编码在iOS中允许开拓者通过 Key 直接待上访问对象的属性,或然给目的的品质也许成员变量赋值,而没有必要调用setter和getter方法。那样就足以在运转时动态在拜见和校勘对象的习性。
  作为能够叫做基类的NSObject有叁个分类NSKeyValueCoding, KVC的概念都是对NSObject的恢宏来促成的,所以对于有着继续了NSObject在档期的顺序,都能使用KVC。
上边就该类中属性方法做分析,同时相配局地例子来展现KVC的效果与利益与实际行使。

在做热修复的长河中,见到JS帕特ch的OC setter方法转义成JavaScript代码时,感觉新奇。代码如下:

二、常见方法

//获取方法- (nullable id)valueForKey:(NSString *)key;- (nullable id)valueForKeyPath:(NSString *)keyPath;- (nullable id)valueForUndefinedKey:(NSString *)key;//可变集合获取方法- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;//设置方法- setValue:(nullable id)value forKey:(NSString *)key;- setValue:(nullable id)value forKeyPath:(NSString *)keyPath;- setValue:(nullable id)value forUndefinedKey:(NSString *)key;- setNilValueForKey:(NSString *)key;

2、属性方法解析:

(1.)

@property (class, readonly) BOOL accessInstanceVariablesDirectly;

该属性用来剖断是不是能一向访谈实例变量,何况是readonly属性的,但在其实使用时实际上是重写类格局 (BOOL)accessInstanceVariablesDirectly; 该类方法暗许重临YES,假诺设置为NO,则只会对点名的key进行精准寻找(e.g: key 为 @"name",则只会对名叫@"name"的质量实行搜索相配,不会在追寻@"name"无结果之处下再去对包蕴name字符的一对别样属性或成员变量可能措施开展检索),若未有结果则直接踏入卓殊方法:取值至极方法 --> - (nullable id)valueForUndefinedKey:(NSString *)key;抑或 赋值非常方法 --> - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

(2.)

- (nullable id)valueForKey:(NSString *)key;

一直通过key来取值。苹果源码中对该办法的叙说使用了汪洋的篇幅(这里就不附加Lithuania语描述了,太长了~),这个描述主要表明了当调用- (nullable id)valueForKey:(NSString *)key; 方法时KVC在在那之中是按什么的次第来搜索key的。
得以达成查找体制如下:

  • 一、首先按 get<Key>,<key>,is<Key> 的依次方法找寻getter方法,即使找到这么的章程的话会平昔调用。同期要是重临值是指标类型则间接回到该目的,倘使是BOOL大概int等底工数据类型, 会做NSNumber调换,不然别的的妄动档案的次序将被转变来NSValue类型重回(今后不光限于NSPoint, NRange, NSRect, and NSSize那三个结构体类型卡塔尔国;

  • 二、假如通过上面包车型大巴秘诀未有找到的话,KVC会查找与-countOf<Key> ,-indexIn<Key>OfObject:,-objectIn<Key>AtIndex:,-<key>AtIndexes: 那些办法名相配的艺术。假诺找到-countOf<Key> ,-indexIn<Key>OfObject:那四个法子和剩下其余三个法子中的一个(起码多个同期设有,同有时间前八个照旧必须的!借使那三个同临时间存在则会事情发生前搜索-objectIn<Key>AtIndex:艺术并赶回依照这一艺术搜索的结果,结果是二个含有八个因素的NSOrderedSet对象卡塔尔(قطر‎,那么就能重返一个能够响应NSOrderedSet(有序聚焦卡塔尔(قطر‎全部办法的代理集结NSKeyValueOrderedSet,调用这些代理集合的章程,恐怕说给这一个代理集结发送NSOrderedSet的措施,就能够以countOf<Key>,-indexIn<Key>OfObject:,objectIn<Key>AtIndex,<Key>AtIndex那多少个主意结合的方式调用,音信被发送给原始接纳者-valueForKey:。假设还完成了叁个可选的点子-get<Ket>:range:艺术, 为了最好的特性该办法就要适度的时候被调用。

  • 三、若是回去有序集中的情势未有找到,KVC会查找与-countOf<Key> ,-objectIn<Key>AtIndex:, -<key>AtIndexes:(对应-[NSArray objectsAtIndexes:]方法State of Qatar这个措施名相称的办法。纵然找到-countOf<Key> 这些方法和剩下别的两个章程中的三个,那么就会回去贰个足以响应NSArray全体方法的代办集合NSKeyValueArray,调用那个代理集合的不二诀窍,大概说给那个代理集结发送NSArray的形式,就能以countOf<Key>,objectIn<Key>AtIndex,<Key>AtIndexs那些点子结合的方式调用,音信被发送给原始选用者-valueForKey:。假使还落到实处了一个可选的章程-get<Key>:range:方法, 为了最好的性格该方式就要适宜的时候被调用。* 在此边确定要分别开和第二步顺序的界别!!!*

  • 四、假设回到数组的法门未有找到,KVC会查找与-countOf<Key>,-enumeratorOf<Key>,and -memberOf<Key>:(对应被NSSet类定义的方法State of Qatar那一个方法名相称的法子。假如那七个章程漫天找到,那么就能回来多个得以响应NSSet全体办法的代办集合NSKeyValueSet,调用这几个代理群集的主意,也许说给那一个代理集结发送NSSet的主意,就能够以-countOf<Key>,-enumeratorOf<Key>,and -memberOf<Key>:那多少个点子结合的款型调用,音讯被发送给原始接受者-valueForKey:。* 在这里地要有别于开和第二步顺序及第三步顺序的区分!!!*

  • 五、假如上述getter方法和集纳的拜访方法均未找到,那么会再检查类方法 (BOOL)accessInstanceVariablesDirectly;,假设回去YES(私下认可行为卡塔尔国,会按_<key>,_is<Key>,<key>,is<Key>的顺序找寻成员变量名,若是找到这么的实例变量那么重临准则与第一步的再次来到值顺序是毫无二致的。假使回去是NO,那么会一向调用- (nullable id)valueForUndefinedKey:(NSString *)key;方法。

  • 六、若通过以上办法均为找到,间接调用- (nullable id)valueForUndefinedKey:(NSString *)key;方法。

看了那般多的表明是或不是有一点点懵,上面大家用代码来分解那总体~:

@interface WMPatchTest@property (nonatomic, strong) NSString *name;@end@implementation WMPatchTest- setName:(NSString *)name { _name = name;}@end

defineClass('WMPatchTest', { setPayCompletion: function { self.setValue_forKey(name, "_name"); },});

三、KVC原理

因而查找头文件NSKeyValueCoding.h注释能够开采KVC的试行进度

  1. valueForKey:(valueForKeyPath:类似)

    • 先是,在指标类中按梯次查找存取器名字为-get<key>, -<key>, -is<key>的法子,假使找到则直接调用,借使格局重返结果类型为指针类型,则平昔重回。假使措施重临结果类型是多少类型扶植NSNumber调换,则赶回NSNumber,不然转产生NSValue并回到(任意类型的结果转变来NSValue,不唯有NSPoint,NSRect和NSSize);
    • 否则,查找-countOf<Key>, -indexIn<Key>OfObject:, -objectIn<Key>AtIndex:-<key>AtIndexes:,如若count方法,index方法和其它三个章程中足足一个措施找到,重返三个能够响应NSOrderedSet全体办法的代办集结对象(NSKeyValueOrderedSet)。各样NSOrderedSet新闻发送给代理集结对象时,当消息发送给原始选拔器的valueForKey:都会被调换来-countOf<Key>, -indexIn<Key>OfObject:, -objectIn<Key>AtIndex:-<key>AtIndexes:的整合来回到。假使实现了可选方法-get<Key>:range:,方法也将被调用来扩充质量优化。
    • 不然(找不到存取器方法和NSOrderedSet访谈方法),查找-countOf<Key>, -objectIn<Key>AtIndex:-<key>AtIndexes:,倘若count方法和其余五个格局中足足二个格局找到,再次回到二个能够响应NSArray全部方法的代办集结对象。各个NSArray音讯发送给代理集结对象时(NSKeyValueArray),当音信发送给原始选拔器的valueForKey:都会被调换到-countOf<Key>, -objectIn<Key>AtIndex:-<key>AtIndexes:的三结合来回到。假如完成了可选方法-get<Key>:range:,方法也将被调用来拓展品质优化。
    • 不然(找不到存取器方法、NSOrderedSet访问方法和array访谈方法),查找-countOf<Key>, -enumeratorOf<Key>-memberOf<Key>:,若是多个办法都找到,重回贰个可以知道响应NSSet全体办法的代理会集对象(NSKeyValueSet)。每一种NSSet新闻发送给代理集合对象时,当新闻发送给原始选取器的valueForKey:都会被调换来-countOf<Key>, -enumeratorOf<Key>-memberOf<key>:的结合来回到。
    • 再不(找不到存取器方法和集合访谈方法),倘若 accessInstanceVariablesDirectly属性再次回到YES,则按梯次查找契合名称_< key >,_is< Key >,< key >, 或者 is< Key >的实例变量。假若找到实例变量,则赶回实例变量的值,调换NSNumber和NSValue同步骤1.
    • 不然(找不到存取器方法,会集访谈方法和实例变量),调用-valueForUndefinedKey:回到结果。-valueForUndefinedKey:的暗中同意完结是抛出叁个NSUndefinedKeyException万分,不过你覆盖此办法。

    注意:

    对于会集(NSArray, NSSet, NSOrderSet卡塔尔(قطر‎像使用普通对象同样,则赶回代理对象,必要完结以下措施

NSArray NSSet NSOrderSet
-countOf<Key> -countOf<Key> -countOf<Key>
-enumeratorOf<Key> -indexIn<Key>OfObject:
One of -memberOf<Key>: One of
-objectIn<Key>AtIndex: -objectIn<Key>AtIndex:
-<key>AtIndexes: -<key>AtIndexes:
Optional (performance) Optional (performance)
-get<Key>:range: -get<Key>:range:
  1. setValue: forKey: (setValue: forKeyPath:类似)

    • 率先,查找类存取器方法-set<Key>:。借使找到此方法规检验参数类型。要是参数类型不是目的指针类型但值是nil,则调用-setNilValueForKey:方法,-setNilValueForKey:办法的暗中认可达成是抛出叁个NSInvalidArgumentException十分,不过你能够覆盖此方式。不然假诺艺术参数类型是目的指针类型,则直接调用此办法并传到value做为参数。若是格局参数类型是此外类型,NSNumber/NSValue的逆调换在方式-valueFor<Key>被调用的时候施行。
    • 不然,假诺 accessInstanceVariablesDirectly属性再次来到YES,则按顺序查找相符名称_< key >,_is< Key >,< key >, 或者 is< Key >的实例变量。要是找到实例变量,而且它的品种是目的指针类型,则对旧值实行release操作,然后对value举办retain操作并赋值给实例变量。如若是别的类型,则一齐骤1进行NSNumber/NSValue实行改造然后再赋值。
    • 不然(未有存取器方法和实例变量),调用setValue:forUndefinedkey:方法,setValue:forUndefinedkey:措施的暗许完毕是抛出一个NSUndefinedKeyException至极,可是你能够覆盖此办法。
  2. 可变集合-mutableArrayValueForKey:key-mutableOrderedSetValueForKey:key-mutableSetValueForKey:key

    暗许实现有取器方法时和-valueForKey:key平等。重回代理对象时必要达成的艺术有间隔。如下:

NSMutableArray / NSMutableOrderedSet NSMutableSet
At least 1 insertion and 1 removal method * At least 1 addition and 1 removal method
-insertObject:in<Key>AtIndex: -add<Key>Object:
-removeObjectFrom<Key>AtIndex: -remove<Key>Object:
-insert<Key>:atIndexes: -add<Key>:
-remove<Key>AtIndexes: -remove<Key>:
Optional (performance) one of * Optional (performance)
-replaceObjectIn<Key>AtIndex:withObject: -intersect<Key>:
-replace<Key>AtIndexes:with<Key>: -set<Key>:
步骤一示例:
Person * person = [[Person alloc] init];
NSString * personName = [person valueForKey:@"name"];
NSLog(@"%@", personName);
//下图中是Person.m中代码

图片 1

身教重于言教代码-1_1

可以看看搜索到-getName方法有结果后就不会再查找了。

图片 2

言传身教代码-1_2

然而上边有一种景况:

图片 3

演示代码-1_3

能够观察此间打字与印刷了null!不是说好的按梯次查找的么?并且下面作者也定义了-valueForUndefinedKey:方法(尚未在图纸中粘出来)相近未有走,那是干吗吗?因为本身定义了名叫name的属性!当你定义了质量后,KVC不会去搜寻-is<Key>方法!
实质上要是有规定的key属性,则只会寻找多个法子: -get<Key>,-<key>,假如那三个点子未有结果,则直接放回null。

图片 4

示范代码-1_4

以下情状全部都以在并未有key属性的动静下進展的操作(再一次重申以下:在一直不key属性的景色下寻觅步骤2,3,4,5,6才有非常大恐怕产生!!!,不然只会招来步骤1中的-get<Key>,-<key>那八个方式)

代码中在应用setKey:value:函数时,用的是_name,直接对protected属性_name赋值。在用@property作属性注解,且getter和setter方法没有都手动同期实现意况下,系统会活动成立八个protected属性,属性名是在property前边加上下划线_ property。

四、实例

//// YKNoteKVCObject.h// YKNote//// Created by wanyakun on 2016/11/10.// Copyright © 2016年 com.ucaiyuan. All rights reserved.//#import <Foundation/Foundation.h>@interface YKNoteKVCObject : NSObject { NSInteger _intVar; NSString *_strVar;}@property (nonatomic, assign) NSInteger intProperty;@property (nonatomic, copy) NSString *strProperty;@end//// YKNoteKVCObject.m// YKNote//// Created by wanyakun on 2016/11/10.// Copyright © 2016年 com.ucaiyuan. All rights reserved.//#import "YKNoteKVCObject.h"@implementation YKNoteKVCObject@synthesize intProperty = _intProperty;@synthesize strProperty = _strProperty;#pragma mark - method for orderSet- (NSUInteger)countOfOrderSet { NSLog(@"%s", __PRETTY_FUNCTION__); return 5;}- (NSInteger)indexInOrderSetOfObject:element { return 2;}- objectInOrderSetAtIndex:(NSUInteger)index { NSLog(@"%s", __PRETTY_FUNCTION__); return [NSString stringWithFormat:@"orderSet_%ld", index];}#pragma mark - method for array- (NSUInteger)countOfArray { NSLog(@"%s", __PRETTY_FUNCTION__); return 10;}- objectInArrayAtIndex:(NSUInteger)index { NSLog(@"%s", __PRETTY_FUNCTION__); return [NSString stringWithFormat:@"array_%ld", index];}#pragma mark - mehtod for set- (NSUInteger)countOfSet { NSLog(@"%s", __PRETTY_FUNCTION__); return 15;}- (NSEnumerator *)enumeratorOfSet { NSLog(@"%s", __PRETTY_FUNCTION__); NSEnumerator *enumerator = [[NSEnumerator alloc] init]; return enumerator;}- (NSString *)memberOfSet:(NSString *)object { NSLog(@"%s", __PRETTY_FUNCTION__); return [NSString stringWithFormat:@"member of set: %@", object];}#pragma mark - method for MutableOrderedSet- insertObject:(NSString *)object inMOrderSetAtIndex:(NSUInteger)index { NSLog(@"%s", __PRETTY_FUNCTION__);}- removeObjectFromMOrderSetAtIndex:(NSUInteger)index { NSLog(@"%s", __PRETTY_FUNCTION__);}#pragma mark - method for MutableArray- insertObject:(NSString *)object inMArrayAtIndex:(NSUInteger)index { NSLog(@"%s", __PRETTY_FUNCTION__);}- removeObjectFromMArrayAtIndex:(NSUInteger)index { NSLog(@"%s", __PRETTY_FUNCTION__);}#pragma mark - method for mutableSet- addMSetObject:(NSString *)object { NSLog(@"%s", __PRETTY_FUNCTION__);}- removeMSetObject:(NSString *)object { NSLog(@"%s", __PRETTY_FUNCTION__);}#pragma mark - private method- valueForUndefinedKey:(NSString *)key { NSLog(@"%snValueForUndefinedKey:%@", __PRETTY_FUNCTION__, key); return @"undefinedKeyValue";}- setNilValueForKey:(NSString *)key { NSLog(@"%snNilValueKey:%@", __PRETTY_FUNCTION__, key);}- setValue:value forUndefinedKey:(NSString *)key { NSLog(@"%snundefineKey:%@", __PRETTY_FUNCTION__, key);}  accessInstanceVariablesDirectly { return YES;}#pragma mark getter setter- (NSInteger)intProperty { NSLog(@"%s", __PRETTY_FUNCTION__); return _intProperty;}- setIntProperty:(NSInteger)intProperty { NSLog(@"%s", __PRETTY_FUNCTION__); _intProperty = intProperty;}- (NSString *)strProperty { NSLog(@"%s", __PRETTY_FUNCTION__); return _strProperty;}- setStrProperty:(NSString *)strProperty { NSLog(@"%s", __PRETTY_FUNCTION__); _strProperty = [strProperty copy];}@end

//// YKNoteKVCViewController.m// YKNote//// Created by wanyakun on 2016/11/11.// Copyright © 2016年 com.ucaiyuan. All rights reserved.//#import "YKNoteKVCViewController.h"#import "YKNoteKVCObject.h"#import <objc/runtime.h>@interface YKNoteKVCViewController ()@property (nonatomic, strong) YKNoteKVCObject *yKNoteKVCObject;@end@implementation YKNoteKVCViewController- viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.title = @"KVC"; self.view.backgroundColor = [UIColor whiteColor]; //通过存取器访问 [self.yKNoteKVCObject setValue:[NSNumber numberWithInteger:10] forKey:@"intProperty"]; NSInteger intProperty = [[self.yKNoteKVCObject valueForKey:@"intProperty"] integerValue]; NSLog(@"intProperty = %ld", intProperty); [self.yKNoteKVCObject setValue:@"I am strProperty" forKey:@"strProperty"]; NSString *strProperty = [self.yKNoteKVCObject valueForKey:@"strProperty"]; NSLog(@"strProperty = %@", strProperty); //通过实例变量访问 [self.yKNoteKVCObject setValue:[NSNumber numberWithInteger:20] forKey:@"intVar"]; NSInteger intVar = [[self.yKNoteKVCObject valueForKey:@"intVar"] integerValue]; NSLog(@"intVar = %ld", intVar); [self.yKNoteKVCObject setValue:@"I am strVar" forKey:@"strVar"]; NSString *strVar = [self.yKNoteKVCObject valueForKey:@"strVar"]; NSLog(@"strVar = %@", strVar); //set undefineKey [self.yKNoteKVCObject setValue:@"undefine value" forKey:@"undefinedKey"]; //为非Object pointer参数类型设置nil [self.yKNoteKVCObject setValue:nil forKey:@"intProperty"]; //NSOrderSet, NSArray, NSSet代理对象 id orderSet = [self.yKNoteKVCObject valueForKey:@"orderSet"]; id array = [self.yKNoteKVCObject valueForKey:@"array"]; id set = [self.yKNoteKVCObject valueForKey:@"set"]; NSLog(@"norderSet class:%@narray class:%@nset class:%@", object_getClass, object_getClass, object_getClass; //NSMutableOrderSet, NSMutableArray, NSMutableSet代理对象 id mutableOrderSet = [self.yKNoteKVCObject mutableOrderedSetValueForKey:@"mOrderSet"]; id mutableArray = [self.yKNoteKVCObject mutableArrayValueForKey:@"mArray"]; id mutableSet = [self.yKNoteKVCObject mutableSetValueForKey:@"mSet"]; NSLog(@"nmutableOrderSet class:%@nmutableArray class:%@nmutableSet class:%@", object_getClass(mutableOrderSet), object_getClass(mutableArray), object_getClass(mutableSet)); }- didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}/*#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation- prepareForSegue:(UIStoryboardSegue *)segue sender:sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller.}*/#pragma mark - getter- (YKNoteKVCObject *)yKNoteKVCObject { if (_yKNoteKVCObject == nil) { _yKNoteKVCObject = [[YKNoteKVCObject alloc] init]; } return _yKNoteKVCObject;}@end

-[YKNoteKVCObject setIntProperty:]-[YKNoteKVCObject intProperty]intProperty = 10-[YKNoteKVCObject setStrProperty:]-[YKNoteKVCObject strProperty]strProperty = I am strPropertyintVar = 20strVar = I am strVar-[YKNoteKVCObject setValue:forUndefinedKey:]undefineKey:undefinedKey-[YKNoteKVCObject setNilValueForKey:]NilValueKey:intPropertyorderSet class:NSKeyValueOrderedSetarray class:NSKeyValueArrayset class:NSKeyValueSetmutableOrderSet class:NSKeyValueFastMutableOrderedSet2mutableArray class:NSKeyValueFastMutableArray2mutableSet class:NSKeyValueFastMutableSet2
步骤二示例:
Person * person = [[Person alloc] init];
id personName = [person valueForKey:@"name"];
NSLog(@"%@", personName);
NSLog(@"%@", NSStringFromClass([personName class]));
//下图中是Person.m中代码

图片 5

演示代码-2_1

图片 6

亲自去做代码-2_2

由地方两图能够见见:重返八个富含多个成分的NSOrderedSet对象,且成分均一致,当中决定成分个数的是-countOf<Key>方法!!示例代码-2_1中结果成分均为@77,示例代码-2_第22中学结果只与-<key>AtIndexes:措施重返值的率先个要素有提到!

本文由新浦京81707con发布于功能介绍,转载请注明出处:KVC访问器实现详细,KVC的原理实现

关键词: 新浦京81707con 原理 iOS基础 详细 KVC

上一篇:使用AVFoundation读取二维码,原生二维码扫描

下一篇:没有了