IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 2021-09-04 -> 正文阅读

[移动开发]2021-09-04

KVC原理

由于使用的是Swift语言,定义的类属性需要加@objc,保证属性添加到运行时方法
如下图:
请图片描述
KVC的内部实现流程,可阅读苹果文档,主要步骤如下,原文翻译的,不清楚可以点击文档查看
取值 value(forKey key: String)
1.valueForKey:的默认实现将一个键参数作为输入,执行以下过程,在接收valueForKey:调用的类实例中进行操作。
在实例中搜索找到的第一个访问器方法,该方法的名称依次为getKey、、is或。如果找到,调用它并继续执行步骤5,并显示结果。否则继续下一步。

2.如果找不到简单的访问器方法,请在实例中搜索名称与模式countOfKey和objectInKeyAtIndex:(对应于NSArray类定义的基本方法)和KeyAtIndex:(对应于NSArray方法objectsatinexes:)匹配的方法。
如果找到了其中的第一个以及其他两个方法中的至少一个,则创建一个集合代理对象,该对象响应所有NSArray方法并返回该对象。否则,继续执行步骤3。
代理对象随后将其接收到的任何NSArray消息转换为countOfKey、objectInKeyAtIndex:、和KeyAtIndex:消息的组合,并转换为创建它的键值编码兼容对象。如果原始对象还实现了一个名为getKey:range:的可选方法,那么代理对象也会在适当的时候使用该方法。实际上,代理对象与键值编码兼容对象一起工作,允许基础属性的行为如同NSArray一样,即使它不是。

3.如果找不到简单的访问器方法或数组访问方法组,请查找名为countOfKey、EnumeratorfKey和memberOfKey:(对应于NSSet类定义的基本方法)的三个方法。
如果找到这三个方法,则创建一个集合代理对象,该对象响应所有NSSet方法并返回该对象。否则,继续执行步骤4。
此代理对象随后将其接收到的任何NSSet消息转换为countOfKey、enumeratorOfKey和memberOfKey:消息的某种组合,并发送给创建它的对象。实际上,代理对象与键值编码兼容对象一起工作,允许基础属性的行为如同NSSet一样,即使它不是NSSet。

4.如果未找到简单的访问器方法或集合访问方法组,并且如果接收方的类方法AccessInstanceVariables直接返回YES,则按该顺序搜索名为key、iskey、key或iskey的实例变量。如果找到,直接获取实例变量的值并继续执行步骤5。否则,继续执行步骤6。

5.如果检索到的属性值是对象指针,只需返回结果。
如果该值是NSNumber支持的标量类型,请将其存储在NSNumber实例中并返回该值。
如果结果是NSNumber不支持的标量类型,请转换为NSValue对象并返回该对象。

6.如果所有其他操作都失败,请调用valueForUndefinedKey:。默认情况下,这会引发异常

2.设置值 setValue:forKey:

1.查找名为setKey:或_setKey的第一个访问器。如果找到,则使用输入值(或根据需要取消包装的值)调用它并完成。
如果找不到简单访问器,并且如果类方法AccessInstanceVariables直接返回YES,请按顺序查找名为“key、\u iskey、key或iskey”的实例变量。如果找到,直接用输入值(或展开值)设置变量并完成。
在找不到访问器或实例变量时,调用setValue:forUndefinedKey:。默认情况下,这会引发异常,但NSObject的子类可能会提供特定于键的行为。

KVC原理流程差不多了解清楚了,还是要自己敲代码,否者纸上谈兵.

1.自定义KVC
//自定义KVC
func xr_setValue(_ value: Any?, forkey key:String) throws
{
if key.count==0 {
return
}

    let Key = key.capitalized //首字母大写
    let func1 = String(format: "set%@", Key)
    let func2 = String(format: "_set%@", Key)
    if responds(to: Selector(func1)) {
        perform(Selector(func1), with: value)
        return
    }
    else if responds(to: Selector(func2))
    {
        perform(Selector(func2), with: value)
        return
    }
    
    /*
     如果上述方法都没有实现 要看accessInstanceVariablesDirectly 是否返回YES
      返回No,抛出异常,为YES就继续寻找 key
     */
     
    if !(self.self as! AnyClass).accessInstanceVariablesDirectly {
        
        throw NSException(name: NSExceptionName("XRUnknownKeyException"), reason: String(format:"[%@ valueForUndefinedKey:]: this class is not key value coding-compliant for the key name %@",self,key), userInfo: nil) as! Error
    }
    
    let marray = getIvarListName()
    let _key = String(format: "_%@", key)
    let _isKey = String(format: "_is%@", Key)
    let isKey = String(format: "is%@", Key)
    if marray.contains(_key) {
        
        let ivar = class_getInstanceVariable(self.self as! AnyClass,(_key as NSString).utf8String!)
        object_setIvar(self, ivar!, value)
        return
    }
    else if marray.contains(_isKey)
    {
        let ivar = class_getInstanceVariable(self.self as! AnyClass,(_isKey as NSString).utf8String!)
        object_setIvar(self, ivar!, value)
        return
    }
    else if marray.contains(isKey)
    {
        let ivar = class_getInstanceVariable(self.self as! AnyClass,(isKey as NSString).utf8String!)
        object_setIvar(self, ivar!, value)
        return
    }
    
    throw NSException(name: NSExceptionName("XRUnknownKeyException"), reason: String(format:"[%@ valueForUndefinedKey:]: this class is not key value coding-compliant for the key name %@",self,key), userInfo: nil) as! Error
}

func getIvarListName()->Array<String>
{
    
    var marray:Array<String>=[]
    let ivars = class_copyIvarList(self.self as! AnyClass, &count)  // class_copyIvarList
    for i in 0..<count
    {
        let ivar = ivars![Int(i)]
        //获取属性名称
        let name = ivar_getName(ivar)
        let key = String(cString: name!)
        marray.append(key)
    }
    free(ivars)
    return marray
}


func xr_value(forKey key: String) throws -> Any? {
    
    if key.count == 0
    {
        return nil;
    }
    
    let Key = key.capitalized
    let getKey = String(format: "get%@", Key)
    let countOfKey = String(format: "countOf%@", Key)
    let objectInkeyAtIndex = String(format: "objectIn%@AtIndex", Key)
    if responds(to: Selector(getKey))
    {
        perform(Selector(getKey))
    }
    else if responds(to: Selector(key))
    {
        perform(Selector(key))
    }
    else if responds(to: Selector(countOfKey))
    {
        if responds(to: Selector(objectInkeyAtIndex))
        {
            let num = perform(Selector(countOfKey)) as! Int
            var mArray:Array<Any>?
            for i in 0..<num {
                mArray?.append(perform(Selector(objectInkeyAtIndex)))
            }
            
            return mArray
        }
    }
    
    //判断是否能够直接赋值实例变量
    if !NSObject.accessInstanceVariablesDirectly {
        
        throw NSException(name: NSExceptionName("XRUnknownKeyException"), reason: String(format:"[%@ valueForUndefinedKey:]: this class is not key value coding-compliant for the key name %@",self,key), userInfo: nil) as! Error
    }


  // 4.找相关实例变量进行赋值
    let marray = getIvarListName()
    let _key = String(format: "_%@", key)
    let _isKey = String(format: "_is%@", Key)
    let isKey = String(format: "is%@", Key)
    if marray.contains(_key) {
        
        let ivar = class_getInstanceVariable(self.self as! AnyClass,(_key as NSString).utf8String!)
       
        return object_getIvar(self, ivar!)
    }
    else if marray.contains(_isKey)
    {
        let ivar = class_getInstanceVariable(self.self as! AnyClass,(_isKey as NSString).utf8String!)
        return object_getIvar(self, ivar!)
       
    }
    else if marray.contains(isKey)
    {
        let ivar = class_getInstanceVariable(self.self as! AnyClass,(isKey as NSString).utf8String!)
      return object_getIvar(self, ivar!)
    }
    
  return ""
    
    
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-05 11:07:57  更:2021-09-05 11:08:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:50:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码