SwiftObject 杂记
一、前言
看了一段时间的Swift,慢慢转变了一些对Swift的看法。
Swift作为苹果新晋的开发语言、具有模板编程、函数编程、协议多继承、vTable静态绑定、值引用类型区分、Option类型等动态语法的多种特性。
Swift作为一门跨平台的语言,非常强调性能,静态绑定是Swift跟OC语言的动态派发迥异的区别。Objetive-C中的Runtime优秀的设计让OC这门语言有着优秀的动态特性,
Swift的语言设计中一部分为了和OC桥接,一部分也参考了OC的设计让Swift具有一些动态特性,比如自省。
Swift强调安全,Optional代替OC中的空指针,同时优化了性能。Optional调用链遇到中间的Optional不会继续执行。同时值类型的语义的大量使用可以规避线程安全带来的问题。
二、本次文章主要探究Swift编译运行机制
1)编写一个控制台程序,将可执行文件拖入Hopper进行反编译
注:下一部分代码借鉴 https://mp.weixin.qq.com/s/zIkB9KnAt1YPWGOOwyqY3Q 《Swift 对象内存模型探究(一)》
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | // // main.swift // TestSwift2 // // Created by lunli on 2018/10/9. // Copyright © 2018年 lunli. All rights reserved. // import Foundation import ObjectiveC class People { var xxxxx = 1 } class Driver : People { var yyyyy = 2 } class SellerPeople { var zzzzz = 3 } struct Person { var name : String var age : Int } class ViewController { var x = 123456 var person : Person ? { didSet { print ( "Called after setting the new value" ) if let name = person ?. name { print ( "New name is \( name ) and old name is \( String ( describing : oldValue ?. name ) )" ) } } willSet ( myNewValue ) { print ( "Called before setting the new value" ) if let newName = myNewValue ?. name { print ( "New name is \( newName )" ) } } } } var p = Driver () print ( type ( of : p )) print ( String . init ( format : "%s" , object_getClassName ( p ))) var v = ViewController () v . person = Person ( name : "1234" , age : 123 ) class Human : ViewController { var age : Int ? var name : String ? var nicknames : [ String ] = [ String ]() //返回指向 Human 实例头部的指针 func headPointerOfClass () - > UnsafeMutablePointer < Int8 > { let opaquePointer = Unmanaged . passUnretained ( self as AnyObject ). toOpaque () let mutableTypedPointer = opaquePointer . bindMemory ( to : Int8 . self , capacity : MemoryLayout < Human > . stride ) return UnsafeMutablePointer < Int8 > ( mutableTypedPointer ) } } let human = Human () let arrFormJson = [ "goudan" , "zhaosi" , "wangwu" ] //拿到指向 human 堆内存的 void * 指针 let humanRawPtr = UnsafeMutableRawPointer ( human . headPointerOfClass ()) //nicknames 数组在内存中偏移 64byte 的位置(16 + 16 + 32) let humanNickNamesPtr = humanRawPtr . advanced ( by : 64 ). assumingMemoryBound ( to : Array < String > . self ) //human.nicknames //[] let test = humanRawPtr . advanced ( by : 0 ). assumingMemoryBound ( to : AnyObject . self ) let test2 = humanRawPtr . advanced ( by : 8 ). assumingMemoryBound ( to : Int64 . self ) print ( test ) humanNickNamesPtr . initialize ( to : arrFormJson ) print ( human . nicknames ) //["goudan","zhaosi", "wangwu"] print (( human as AnyObject ). isKind ( of : ViewController . self )) |
拖入Hopper之后,可以看到
我们可以清晰看到SellerPeople的类的定义,和其MetaClass的定义;其定义跟现有的OC Class类型定义比较类似,一个指针指向父类,一个指向元类,Cache未知、一个vtable表示方法调用列表、data表示类中的变量数据
上面的截图可以看到SellerPeople中ivar的定义和名字方法的定义、通过这些信息可以完全实现一个对象类型的检测、属性列表、方法列表等。
在DEBUG模式生成的可执行文件下面,我们用命令行对其中的符号进行恢复,可以清晰看到类名、变量名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | LUNLI - MC1 : Swift 二进制分析 lunli $ nm TestSwift2 | xcrun swift - demangle | grep "ViewController" 0000000100002120 t TestSwift2 . ViewController . person . didset : TestSwift2 . Person ? 0000000100002ae0 T TestSwift2 . ViewController . person . getter : TestSwift2 . Person ? 0000000100002d70 T TestSwift2 . ViewController . person . materializeForSet : TestSwift2 . Person ? 0000000100002d40 t closure # 1 : () in TestSwift2 . ViewController . person . materializeForSet : TestSwift2 . Person ? 00000001004f3cd8 S direct field offset for TestSwift2 . ViewController . person : TestSwift2 . Person ? 0000000100002110 T variable initialization expression of TestSwift2 . ViewController . person : TestSwift2 . Person ? 0000000100002b60 T TestSwift2 . ViewController . person . setter : TestSwift2 . Person ? 00000001000026f0 t TestSwift2 . ViewController . person . willset : TestSwift2 . Person ? 0000000100002e10 T TestSwift2 . ViewController . __allocating_init () - > TestSwift2 . ViewController 0000000100002f60 T TestSwift2 . ViewController . init () - > TestSwift2 . ViewController 0000000100511110 s reflection metadata field descriptor TestSwift2 . ViewController 0000000100589e38 b lazy cache variable for type metadata for TestSwift2 . ViewController 0000000100001cd0 T type metadata accessor for TestSwift2 . ViewController 0000000100584d60 d full type metadata for TestSwift2 . ViewController 0000000100584d38 D metaclass for TestSwift2 . ViewController 00000001004f3cf0 S nominal type descriptor for TestSwift2 . ViewController 0000000100584d70 D type metadata for TestSwift2 . ViewController 0000000100003030 T TestSwift2 . ViewController . __deallocating_deinit 0000000100002fd0 T TestSwift2 . ViewController . deinit 0000000100589ad8 S TestSwift2 . v : TestSwift2 . ViewController 0000000100507a0e s _symbolic ____ 10TestSwift214ViewControllerC |
2)既然能看到任意swift定义的class结构,那么 swift是否存在一个共同的父类结构?
搜索之后看到一个答案:
原文:https://stackoverflow.com/questions/24137368/why-is-there-no-universal-base-class-in-swift
我写了一点代码来模拟这个特性,一段OC和Swift混编的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | import Foundation class People { var xxxxx = 1 } class Driver : People { var yyyyy = 2 } class SellerPeople { var zzzzz = 3 } struct Person { var name : String var age : Int } class ViewController1 : NSObject { var obj = SellerPeople () @objc var str = "Hello World" var x = 123456 var person : Person ? { didSet { print ( "Called after setting the new value" ) if let name = person ?. name { print ( "New name is \( name ) and old name is \( String ( describing : oldValue ?. name ) )" ) } } willSet ( myNewValue ) { print ( "Called before setting the new value" ) if let newName = myNewValue ?. name { print ( "New name is \( newName )" ) } } } @objc func getSwiftObj () - > AnyObject { return obj } } class Human : ViewController1 { var age : Int ? var name : String ? var nicknames : [ String ] = [ String ]() //返回指向 Human 实例头部的指针 func headPointerOfClass () - > UnsafeMutablePointer < Int8 > { let opaquePointer = Unmanaged . passUnretained ( self as AnyObject ). toOpaque () let mutableTypedPointer = opaquePointer . bindMemory ( to : Int8 . self , capacity : MemoryLayout < Human > . stride ) return UnsafeMutablePointer < Int8 > ( mutableTypedPointer ) } } |
注意getSwiftObject方法返回的是一个Swift对象,我们将这个对象拿到OC中用调试器进行调试
可以看到调试器中打印出来,一个纯Swift没有指定父类的类默认继承的对象是SwiftObject,参考这个类的实现如下
https://github.com/apple/swift/blob/f4db1dd7a4abba2685247e1a7415d4fcb91f640d/stdlib/public/runtime/SwiftObject.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | //===--- SwiftObject.h - Native Swift Object root class ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This implements the Objective-C root class that provides basic `id`- // compatibility and `NSObject` protocol conformance for pure Swift classes. // //===----------------------------------------------------------------------===// #ifndef SWIFT_RUNTIME_SWIFTOBJECT_H #define SWIFT_RUNTIME_SWIFTOBJECT_H #include "swift/Runtime/Config.h" #include <cstdint> #include <utility> #include "swift/Runtime/HeapObject.h" #if SWIFT_OBJC_INTEROP #include "llvm/Support/Compiler.h" #include <objc/NSObject.h> #endif #if SWIFT_OBJC_INTEROP #if SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT // Source code: "SwiftObject" // Real class name: mangled "Swift._SwiftObject" #define SwiftObject _TtCs12_SwiftObject #else // Pre-stable ABI uses un-mangled name for SwiftObject #endif #if __has_attribute(objc_root_class) __attribute__((__objc_root_class__)) #endif SWIFT_RUNTIME_EXPORT @interface SwiftObject< NSObject > { @private Class isa; SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS; } - ( BOOL )isEqual:( id )object; - ( NSUInteger )hash; - (Class)superclass; - (Class) class ; - (instancetype) self ; - ( struct _NSZone *)zone; - ( id )performSelector:( SEL )aSelector; - ( id )performSelector:( SEL )aSelector withObject:( id )object; - ( id )performSelector:( SEL )aSelector withObject:( id )object1 withObject:( id )object2; - ( BOOL )isProxy; + ( BOOL )isSubclassOfClass:(Class)aClass; - ( BOOL )isKindOfClass:(Class)aClass; - ( BOOL )isMemberOfClass:(Class)aClass; - ( BOOL )conformsToProtocol:(Protocol *)aProtocol; - ( BOOL )respondsToSelector:( SEL )aSelector; + ( BOOL )instancesRespondToSelector:( SEL )aSelector; - (IMP)methodForSelector:( SEL )aSelector; + (IMP)instanceMethodForSelector:( SEL )aSelector; - (instancetype)retain; - (oneway void )release; - (instancetype)autorelease; - ( NSUInteger )retainCount; - ( NSString *)description; - ( NSString *)debugDescription; @end namespace swift { NSString *getDescription(OpaqueValue *value, const Metadata *type); } #endif #endif |
这个类包含一个实例变量isa,这个Class是一个指针,指向的是OC Runtime中类定义的结构;同时这个类实现了NSObject的协议,猜测这样的设计是为了跟OC进行桥接。
3)Swift的对象的内存布局
这里的内容主要来自第一篇提到的文章,一个Swift引用指向的内存区域,
第一个指针应该是isa,
第二个8字节(32位机器为4字节)为引用计数,
第三块区域是vtable指针,
接下来的是继承的变量
接下来是这个类实现的变量
可见这里的对象内存布局和C++有些类似,但是增加了一个isa的东西,让这个对象具有了一些动态特征。方法执行采用vtable寻址的方式,快速高效。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架