一、前言

  看了一段时间的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 对象内存模型探究(一)》

//
// 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模式生成的可执行文件下面,我们用命令行对其中的符号进行恢复,可以清晰看到类名、变量名。

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混编的代码

  

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

//===--- 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寻址的方式,快速高效。

    

SwiftObject 杂记的更多相关文章

  1. [Erlang 0118] Erlang 杂记 V

       我在知乎回答问题不多,这个问题: "对你职业生涯帮助最大的习惯是什么?它是如何帮助你的?",我还是主动回答了一下.    做笔记 一开始笔记软件做的不好的时候就发邮件给自己, ...

  2. Ubuntu杂记——Ubuntu下用虚拟机共享上网

    由于最近把自己电脑环境换成了Ubuntu,但学校的网络是电信的闪讯,大学里用过的人都知道这货有多坑,而且没有Linux客户端,上网都是问题,怪不得国内用Linux的人那么少,特别是高校的学生(让我瞎逼 ...

  3. 一个ubuntu phper的自我修养(杂记)

    ubuntu使用杂记 1.flatabulous安装使用. flatabulous是一个ubuntu图标主题. 使用它,必须得安装tweak插件. sudo add-apt-repository pp ...

  4. 有关Java的日期处理的一些杂记

    在企业应用开发中,经常会遇到日期的相关处理,说实话JDK自带的日期方法很难用.就我个人而言我一般都会采用joda-time来替代JDK自身的日期. 这篇文章是杂记,所以写的比较零散,希望大家不要见怪. ...

  5. 分布式系统之CAP理论杂记[转]

    分布式系统之CAP理论杂记 http://www.cnblogs.com/highriver/archive/2011/09/15/2176833.html 分布式系统的CAP理论: 理论首先把分布式 ...

  6. Redis杂记

    参考资料: Redis 教程 | 菜鸟教程 : http://www.runoob.com/redis/redis-tutorial.html Redis快速入门 :http://www.yiibai ...

  7. MySQL杂记

    参考资料: w3school  SQL 教程 : http://www.w3school.com.cn/sql/index.asp 21分钟 MySQL 入门教程 : http://www.cnblo ...

  8. Android之开发杂记(一)

    1.cygwin环境变量设置 可在Cygwin.bat 中设置 set NDK_ROOT=P:/android/android-ndk-r8e 或者在home\Administrator\.bash_ ...

  9. ios程序开发杂记

    ios程序开发杂记 一.程序构建 与一般的程序构建无太大区别,都是源文件编译链接这一套,通常是在mac上做交叉编译,也就是利用xcode里带的ios编译工具集去生成arm架构的ios程序(或是x86的 ...

  10. [Flask]学习杂记--模板

    这个学习杂记主要不是分享经验,更多是记录下falsk的体验过程,以后做东西在深入研究,因为django之前用的时间比较长,所以很多概念都是一看而过,做个试验了解下flask的功能. flask中使用是 ...

随机推荐

  1. docker 应用篇————docker 网络[十七]

    前言 简单介绍一下docker 网络. 正文 使用ip addr. 可以看到网络. 有一个虚拟网卡: 那么基本上容器就处于这样的模式了. 那么也就是所有容器都在同一网关下面了. 那么问题来了,理论上容 ...

  2. python实现:有一个列表为num_list,找到一个具有最大和的连续子列表,返回其最大和。

    # 有一个列表为num_list,找到一个具有最大和的连续子列表,返回其最大和.# 示例:# 输入: [-3,1,-1,6,-1,2,4,-5,4]# 输出: 11# 解释: 连续子数组 [6,-1, ...

  3. locust常用的配置参数【locust版本:V1.1.1】

    locust 官网文档地址:https://docs.locust.io/en/stable/configuration.html Locust QQ 群: 执行命令如: master: locust ...

  4. 2024-04-17:用go语言,欢迎各位勇者莅临力扣城,本次的挑战游戏名为「力扣泡泡龙」。 游戏的起点是一颗形状如二叉树的泡泡树,其中每个节点的值代表该泡泡的分值。勇者们有一次机会可以击破一个节点泡

    2024-04-17:用go语言,欢迎各位勇者莅临力扣城,本次的挑战游戏名为「力扣泡泡龙」. 游戏的起点是一颗形状如二叉树的泡泡树,其中每个节点的值代表该泡泡的分值.勇者们有一次机会可以击破一个节点泡 ...

  5. 从Vue2转换为Vue3

    方便的Vue2到Vue3生命周期映射直接来自Vue3 Composition API文档,我认为这是了解事物将如何变化以及如何使用它们的最有用的方法之一. beforeCreate -> use ...

  6. 力扣178(MySQL)-分数排名(中等)

    题目: 表: Scores 编写 SQL 查询对分数进行排序.排名按以下规则计算: 分数应按从高到低排列.如果两个分数相等,那么两个分数的排名应该相同.在排名相同的分数后,排名数应该是下一个连续的整数 ...

  7. 谈谈JVM内部锁升级过程

    简介: 对象在内存中的内存布局是什么样的?如何描述synchronized和ReentrantLock的底层实现和重入的底层原理?为什么AQS底层是CAS+volatile?锁的四种状态和锁升级过程应 ...

  8. gitlab-ce-15.9.4安装

    如果需要汉化版本,请根据汉化来选择版本 汉化包下载地址:https://gitlab.com/xhang/gitlab/ 1.依赖包安装 yum -y install policycoreutils- ...

  9. vue+element设置选择日期最大范围(普通版)

    效果是只能跟当天时间有关(30天),下一篇将来的任意时段,比较符合实际 <!DOCTYPE html> <html> <head> <meta charset ...

  10. Oracle和达梦:相似度函数:UTL_MATCH

    UTL_MATCH介绍: Oracle的UTL_MATCH包是一个提供字符串匹配和相似度计算功能的工具包.它包含了一系列函数,用于执行字符串比较.相似度计算和模式匹配等操作. UTL_MATCH包中的 ...