博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HandyJSON实现方案浅析
阅读量:5906 次
发布时间:2019-06-19

本文共 2477 字,大约阅读时间需要 8 分钟。

简述

近日,由于Swift升级,导致一段时间HandyJSON无法使用,借这个机会将HandyJSON好好学习了一下~ 然后从另一种方式实现了类似OC的KVC效果的一个小Demo,通过本文记录一些自己的收获,旨在抛砖引玉,有错误的地方还请多多指正 ~ (๑•ᴗ•๑)

好了,下面先从Swift的类型结构开始谈起吧~

MetaDate

Swift在运行时为程序中的每个类型都保留了元数据用于记录(类比OC的元类),包括每个泛型类型的实例.这些数据都是由编译器静态生成,且每种类型都有唯一的元数据记录.元数据在运行时根据需要进行延迟创建~ MetaData的信息 就存储在类别指针的第一个字节中.

Swift将MetaData做以下分类~

现在主要关注 ClassStruct中, 先说Class 从上面文档中的描述 我们可知 所有Apple平台的Swift的类都要与OC的类交互,也就是说 Swift的类别指针就是isa指针.

所以SwiftOCClass 在本质上是一样,只不过Swift剔除其中的动态特性~ 这也是SwiftOC间可以无缝交互的原因之一 ~

上面的内容是Swift Github的文档,大家感兴趣可以看看~ 接下来 我先分析下HandyJSON的实现方式,然后再说说我自己的实现方式.

HandyJSON

实现思路

HandyJSON的实现的内容大概是这样的:JSON转字典,同时处理自定义映射的内容 --> 获取对象/结构体 属性的内存位置,然后将值写入~ 而其中最核心的内容就是 获取对象/结构体的属性列表与偏移量.

HandyJSON是通过元数据的Nominal Type Descriptor来获取的~ 这是定义的结构体

struct _NominalTypeDescriptor {    var mangledName: Int32    var numberOfFields: Int32    var fieldOffsetVector: Int32    var fieldNames: Int32    var fieldTypesAccessor: Int32}复制代码

这个结构体中就包含了全部需要的内容,只要得到它,接下来就是将内容写入和封装的事了~ 下面就是获取**_NominalTypeDescriptor**的代码,

var nominalTypeDescriptor: NominalTypeDescriptor? {        let pointer = UnsafePointer
(self.pointer) let base = pointer.advanced(by: nominalTypeDescriptorOffsetLocation) if base.pointee == 0 { // swift class created dynamically in objc-runtime didn't have valid nominalTypeDescriptor return nil } #if swift(>=4.1) || (swift(>=3.3) && !swift(>=4.0)) return NominalTypeDescriptor(pointer: relativePointer(base: base, offset: base.pointee - base.hashValue)) #else return NominalTypeDescriptor(pointer: relativePointer(base: base, offset: base.pointee)) #endif}复制代码

这部分内容也是在Swift更新后出问题的地方.在文档中关于这里的部分表示Warning: this is all out of date!,可能作者是通过Swift源码分享确定**_NominalTypeDescriptor**的位置的吧~

我这里就是简单介绍一下,详细的内容 大家还是去看源码吧~ 接下来是我的实现思路

我的实现方式

我写了个Demo 实现的效果大概如下,还有不少瑕疵需要改进,但基本做到KVC的效果了~

Class

对于Class我的思路是这样的,由文档可知,我们能获得isa指针,接下来要做的就是根据OC runtime源码,实现其中需要的类型,然后通过指针进行类型强制转换,这样就得到 我们需要的内容了~

但是 我在实现这块的时候 出现了一些问题 对于ivar结构体时,获取的内容与runtime中的有差异,而且只能获取 属性名称和偏移量(主要这里有些困惑,若有懂的老铁 还请指点一下~)

struct MK_ivar {                var mask1:Int32                var off:UnsafePointer
var name:UnsafePointer
var mask2:UInt32 var mask3:UInt32 }复制代码

关于属性类型 我则是通过Mirror来获取的,这样就得到需要的全部信息了.

Struct

Struct则很简单了,在Mirror中获取属性的顺序和结构体中分部的属性是一样的,通Mirror获取属性类型,然后推断出它在结构体中填充的大小,这样各个属性的偏移量就得到了,接下来只要将Value写入就好了~

总结

这是链接,还有一些瑕疵~后续我将其改进,若感觉对你有帮助的话 可以点个Star (๑•ᴗ•๑)

转载地址:http://ghcpx.baihongyu.com/

你可能感兴趣的文章
脚本开胃菜
查看>>
linux_oracle安装说明
查看>>
做原型设计的软件
查看>>
CentOS7.2 设置静态ip
查看>>
js的DOM编程艺术的笔记(二)
查看>>
SQL中的正则表达式(REGEXP)
查看>>
如何选择加密锁?
查看>>
第一章 虚拟化 安装ESXI
查看>>
锁屏时Activity的生命周期变化
查看>>
React入门看这篇就够了
查看>>
json封装
查看>>
MFC模态对话与非模态对话框(一)
查看>>
021 简单链路追踪 - zipkin
查看>>
List,Set,Map的遍历
查看>>
LNAMP源码安装整合加论坛及动静分离
查看>>
Oracle学习笔记之第一节实验环境介绍及推送过程
查看>>
Can't connect to local MySQL server through socket '/tmp/mysql.sock'
查看>>
linux下iptables命令
查看>>
博为峰Java技术题 ——JavaSE 避免死锁Ⅱ
查看>>
JavaSE 学习参考:构造方法
查看>>