所在的位置: swift >> swift发展 >> Swift5TypeMetadat

Swift5TypeMetadat

视频网站免费vip账号 https://www.edunews.net.cn/2021/ywbb_0924/139075.html
背景

Swift5出了,主要是ABI稳定了,从ABIDashboard来看为了解决ABI稳定问题,对typemetadata也有不少改动。众所周知,我们App的JSON库HandyJSON是强依赖metadata结构的,如果metadata有大规模的改动可能直接导致这个库完全不能用,本着早发现早治疗的心态我赶快下载了Xcode10.2beta,一跑果然编不过了,没办法只好自己着手来解决问题了。

Metadata的结构演进

为了便于理解,先画个图看一下metadata的具体结构,每一格代码一个指针长度,这是64位系统下的metadata结构,32位系统下nominaltypedescriptor的偏移在11个指针长度的位置,官方文档里有详细的说明。Swifttypemetadata的结构其实并没有明显的变化,而其中的nominaltypedescriptor结构却经历了一系列的变化。

Swift4.2以前

在Swift4.2(不包括4.2)以前的结构是这样的:

struct_NominalTypeDescriptor{varmangledName:Int32varnumberOfFields:Int32varfieldOffsetVector:Int32varfieldNames:Int32varfieldTypesAccessor:Int32}

复制代码nominaltypedescriptor包含了属性的名字和访问属性的类型信息的函数,HandyJSON最初的原理就是从nominaltypedescriptor中取得属性的类型信息然后把JSON字串里的相应值赋进去,由于fieldTypeAccessor符合c的callingconvention,把指针强转一下就能获得类型信息:

varfieldTypes:[Any.Type]?{guardletnominalTypeDescriptor=self.nominalTypeDescriptorelse{returnnil}guardletfunction=nominalTypeDescriptor.fieldTypesAccessorelse{returnnil}return(0..nominalTypeDescriptor.numberOfFields).map{returnunsafeBitCast(function(UnsafePointerInt(pointer)).advanced(by:0).pointee,to:Any.Type.self)}}

Swift4.2

Swift4.2对nominaltypedescriptor做了调整,struct和class结构变得有所不同,乍看没有少什么东西,其实对fieldTypesAccessor这个函数做了修改,不再符合c的callingconvention,因此不可以再从nominaltypedescriptor获取类型信息。

struct_StructContextDescriptor:_ContextDescriptorProtocol{varflags:Int32varparent:Int32varmangledName:Int32varfieldTypesAccessor:Int32varnumberOfFields:Int32varfieldOffsetVector:Int32}struct_ClassContextDescriptor:_ContextDescriptorProtocol{varflags:Int32varparent:Int32varmangledName:Int32varfieldTypesAccessor:Int32varsuperClsRef:Int32varreservedWord1:Int32varreservedWord2:Int32varnumImmediateMembers:Int32varnumberOfFields:Int32varfieldOffsetVector:Int32}

尽管苹果希望我们用Mirror来做反射,但是其实Mirror至今为止都不包含属性的类型的信息,因此苹果留了一个临时接口swift_getFieldAt来帮助我们获取类型信息:

_silgen_name("swift_getFieldAt")func_getFieldAt(_type:Any.Type,_index:Int,_callback:

convention(c)(UnsafePointerCChar,UnsafeRawPointer,UnsafeMutableRawPointer)-Void,_ctx:UnsafeMutableRawPointer)

为什么说是临时的呢,因为Swift5的时候就发现这个接口没了。。。。

Swift5.0

到了Swift5.0的时候,前面已经说过了获取类型的那个接口没了,那么我们只好翻出Swift的源码来找找思路了,找到TypeContextDescriptorBuilderBase类的layout()方法:

voidlayout(){asImpl().


转载请注明:http://www.aierlanlan.com/tzrz/279.html

  • 上一篇文章:
  •   
  • 下一篇文章: