KVC访问器实现详细

作者: 桃红宿雨 | 来源:发表于2016-10-22 12:21 被阅读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的设置方法使用很频繁,深入理解内部细节有助于我们开发提供更多思路,遇到异常情况时思路更清晰~

相关文章

  • KVC访问器实现详细

    前言 本文翻译自苹果文档Accessor Search Implementation Details及方法的注释。...

  • KVC/KVO实现原理

    原文 KVC如何访问属性值 KVC再某种程度上提供了访问器的替代方案。不过访问器方法是一个很好的东西,以至于只要是...

  • Key-Value Coding(键值编码)

    一、KVC简介 KVC提供了一套不通过访问器方法或者属性变量,通过Key或者KeyPath直接访问对象属性的机制。...

  • 6.iOS消息传递的方式

    1.KVC实现原理 KVC, 键-值编码,使用字符串直接访问对象属性. 底层实现, 当一个对象调用setValue...

  • KVC/KVO的理解

    KVC KVC实现了基于KEY访问对象属性的一套查找规则,可以直接操作对象的属性,变量即使设置为私有的也一样访问。...

  • KVC是怎么访问属性的?KVO怎么实现的?

    KVC是怎么访问属性的 KVC在某种程度上提供了替代存取方法(访问器方法)的方案,不过存取方法终究是个好东西,以至...

  • KVO

    核心原理KVO是建立在KVC的基础上。只有在使用KVC准则访问访问器或成员变量的情况下,才可以监视属性的变化。NS...

  • KVO

    在使用kvo进行监听的时候,如何触发KVO回调 1)使用 KVC 方法如果存在访问器方法,则会调用访问器方法, 访...

  • 【iOS开发】基础知识

    1. KVC的使用?实现原理? KVC提供了一种间接访问其属性方法或成员变量的机制,可以通过字符串来访问对应的属性...

  • KVC 与 KVO 使用和原理解析

    KVC 什么是 KVC KVC 主要方法 KVC 定义了一种按名称访问对象属性的机制,支持这种访问的主要方法是: ...

网友评论

    本文标题:KVC访问器实现详细

    本文链接:https://www.haomeiwen.com/subject/yxqhuttx.html