iOS移动开发社区iOS开发iOS学习

KVC访问器实现详细

2016-10-22  本文已影响123人  桃红宿雨

前言

本文翻译自苹果文档Accessor Search Implementation Details及方法的注释。翻译的不对的地方还请多多包涵指正,谢谢~

翻译背景

在做热修复的过程中,看到JSPatch的OC setter方法转义成JavaScript代码时,感到奇妙。代码如下:

@interface WMPatchTest
@property (nonatomic, strong) NSString *name;
@end

@implementation WMPatchTest
- (void)setName:(NSString *)name {
    _name = name;
}
@end
defineClass('WMPatchTest', {
    setPayCompletion: function(name) {
        self.setValue_forKey(name, "_name");
    },
});

代码中在使用setKey:value:函数时,用的是_name,直接对protected属性_name赋值。在用@property作属性声明,且getter和setter方法没有都手动同时实现情况下,系统会自动创建一个protected属性,属性名是在property前面加上下划线_ property。

Then,若想再深入具体了解KVC,请看下面翻译的苹果文档~

KVC访问器实现详细

在KVC直接访问实例变量前,会尝试使用属性的访问方法。本篇文章讲述了KVC是如何决定用哪种方法访问属性。

对于简单属性的-setValue:forKey:

-setValue:forKey:方法对一个属性的默认实现调用后,判断执行的顺序如下:

  1. 首先搜索调用类的实例方法,实例方法的名字模式是set<Key>(即set字符串和key值的组合)。如果方法找到了,系统还会校验方法参数。如果参数类型不是对象指针(id),但参数值为nil,则-setNilValueForKey:被调用。-setNilValueForKey:默认实现会抛出一个NSInvalidArgumentException异常,但你可以重写这个方法的实现。如果参数类型是对象指针,方法会简单地校验通过。若参数类型是其他类型(比如,int,CGPoint等),在方法-valueForKey:调用前会自动把这些类型转换成NSNumber或NSValue;
  2. 如果方法没找到,而且调用该方法的类方法+accessInstanceVariablesDirectly返回的是YES,那么会查找该类实例的变量名字,依次匹配这些样式:_<key>, _is<Key>, <key>, is<Key>。如果找到匹配的变量,且变量是对象型,那么对象引用计数会增1且变量也会被赋值,之后原来变量指向的旧值引用计数会减1。若实例变量是其他类型(比如,int,CGPoint等),会想步骤1中一样,先把NSNumber或NSValue转成非对象类型再赋值;
  3. 否则(方法和实例变量都没找到),会调用-setValue:forUndefinedKey:方法。该方法默认实现会抛出一个NSUndefinedKeyException异常,但你可以重写它;

兼容性注意:

  • 对于-takeValue:forKey:方法的向后二进制兼容,在步骤1中若方法名模式是-_set<Key>:也会被识别。不过在Mac10.3系统后,KVC中以下划线开头的模式方法已废弃;
  • 对于向后二进制兼容性,如果调用类参数不是对象型,则在步骤1中-unableToSetNilForKey:方法会代替-setNilValueForKey:调用;
  • 步骤2中描述的行为与-takeValue:forKey:不同,后者在搜索类实例变量时只会去依次匹配<key>, _<key>模式;
  • 步骤3中对于-takeValue:forKey:方法,如果调用类参数不是对象型,-handleTakeValue:forUnboundKey:会代替-setValue:forUndefinedKey:的调用;

栗子分析

再回头看背景介绍的例子,name是WMPatchTest类属性,编译器会自动生成setter方法-setName:,getter方法-name,及私有变量_name。执行[WMPatchTest setValue:@"xx" forKey:@"_name"]时,首先进行步骤1,查找名字为set_name方法。发现没有后,进行步骤2,检查发现+accessInstanceVariablesDirectly为YES后(默认是YES),依次让类变量匹配这些样式:_name, _isName, name, isName_name被匹配并执行赋值操作;

后语

开发中,KVC的设置方法使用很频繁,深入理解内部细节有助于我们开发提供更多思路,遇到异常情况时思路更清晰~

上一篇下一篇

猜你喜欢

热点阅读