iOS开发-Swift进阶之类、对象、属性!

本文主要介绍以下几点,文章最后会总结

  • 通过SIL来理解对象的创建

  • Swift类结构分析

  • 存储属性 & 计算属性

  • 延迟存储属性 & 单例创建方式

SIL

在底层流程中,OC代码和SWift代码时通过不同的编译器进行编译,然后通过LLVM,生成.o可执行文件,如下所示

SIL-1

  • OC中通过clang编译器(clang可以参考这篇文章iOS-底层原理 31:LLVM编译流程 & Clang插件开发),编译成IR,然后再生成可执行文件.o(即机器码)

  • swift中通过swiftc编译器,编译成IR,然后再生成可执行文件

下面是Swift中的编译流程,其中SIL(Swift Intermediate Language),是Swift编译过程中的中间代码,主要用于进一步分析和优化Swift代码。如下图所示,SIL位于在ASTLLVM IR之间

SIL-2

注意:这里需要说明一下,Swift与OC的区别在于 Swift生成了高级的SIL

我们可以通过swiftc -h终端命令,查看swiftc的所有命令

SIL-3

例如:在main.swift文件定义如下代码

class CJLTeacher{    var age: Int = 18    var name: String = "CJL"}var t = CJLTeacher()
  • 查看抽象语法树:swiftc -dump-ast main.swift

    SIL-4

*   生成SIL文件:`swiftc -emit-sil main.swift >> ./main.sil && code main.sil`,其中main的入口函数如下
// main
//`@main`:标识当前main.swift的`入口函数`,SIL中的标识符名称以`@`作为前缀
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
//`%0、%1` 在SIL中叫做寄存器,可以理解为开发中的常量,一旦赋值就不可修改,如果还想继续使用,就需要不断的累加数字(注意:这里的寄存器,与`register read`中的寄存器是有所区别的,这里是指`虚拟寄存器`,而`register read`中是`真寄存器`)
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
//`alloc_global`:创建一个`全局变量`,即代码中的`t`
  alloc_global @$s4main1tAA10CJLTeacherCvp        // id: %2
//`global_addr`:获取全局变量地址,并赋值给寄存器%3
  %3 = global_addr @$s4main1tAA10CJLTeacherCvp : $*CJLTeacher // user: %7
//`metatype`获取`CJLTeacher`的`MetaData`赋值给%4
  %4 = metatype $@thick CJLTeacher.Type           // user: %6
//将`__allocating_init`的函数地址赋值给 %5
  // function_ref CJLTeacher.__allocating_init()
  %5 = function_ref @$s4main10CJLTeacherCACycfC : $@convention(method) (@thick CJLTeacher.Type) -> @owned CJLTeacher // user: %6
//`apply`调用 `__allocating_init` 初始化一个变量,赋值给%6
  %6 = apply %5(%4) : $@convention(method) (@thick CJLTeacher.Type) -> @owned CJLTeacher // user: %7
//将%6的值存储到%3,即全局变量的地址(这里与前面的%3形成一个闭环)
  store %6 to %3 : $*CJLTeacher                   // id: %7
//构建`Int`,并`return`
  %8 = integer_literal $Builtin.Int32, 0          // user: %9
  %9 = struct $Int32 (%8 : $Builtin.Int32)        // user: %10
  return %9 : $Int32                              // id: %10
} // end sil function 'main'

注意:code命令是在.zshrc中做了如下配置,可以在终端中指定软件打开相应文件

$ open .zshrc
//****** 添加以下别名
alias subl='/Applications/SublimeText.app/Contents/SharedSupport/bin/subl'
alias code='/Applications/Visual\ Studio\ Code.app/Contents/Resources/app/bin/code'

//****** 使用
$ code main.sil

//如果想SIL文件高亮,需要安装插件:VSCode SIL
  • 从SIL文件中,可以看出,代码是经过混淆的,可以通过以下命令还原,以s4main1tAA10CJLTeacherCvp为例:xcrun swift-demangle s4main1tAA10CJLTeacherCvp

    图片

    SIL-5

  • 在SIL文件中搜索s4main10CJLTeacherCACycfC,其内部实现主要是分配内存+初始化变量

  • allocing_ref:创建一个CJLTeacher的实例对象,当前实例对象的引用计数为1

  • 调用init方法

//********* main入口函数中代码 *********
%5 = function_ref @$s4main10CJLTeacherCACycfC : $@convention(method) (@thick CJLTeacher.Type) -> @owned CJLTeacher 

// s4main10CJLTeacherCACycfC 实际就是__allocating_init()
// CJLTeacher.__allocating_init()
sil hidden [exact_self_class] @$s4main10CJLTeacherCACycfC : $@convention(method) (@thick CJLTeacher.Type) -> @owned CJLTeacher {
// %0 "$metatype"
bb0(%0 : $@thick CJLTeacher.Type):
// 堆上分配内存空间
  %1 = alloc_ref $CJLTeacher                      // user: %3
  // function_ref CJLTeacher.init() 初始化当前变量
  %2 = function_ref @$s4main10CJLTeacherCACycfc : $@convention(method) (@owned CJLTeacher) -> @owned CJLTeacher // user: %3
  // 返回
  %3 = apply %2(%1) : $@convention(method) (@owned CJLTeacher) -> @owned CJLTeacher // user: %4
  return %3 : $CJLTeacher                         // id: %4
} // end sil function '$s4main10CJLTeacherCACycfC'

SIL语言对于Swift源码的分析是非常重要的,关于其更多的语法信息,可以在这个网站进行查询

符号断点调试

  • 在demo中设置_allocing_init符号断点

    SIL-6

    发现其内部调用的是swift_allocObject

    SIL-7

源码调试

下面我们就通过swift_allocObject来探索swift中对象的创建过程

  • REPL(命令交互行,类似于python的,可以在这里编写代码)中编写如下代码(也可以拷贝),并搜索swift_allocObject函数加一个断点,然后定义一个实例对象t

    SIL-8

  • 断点断住,查看左边local有详细的信息

SIL-9

  • 其中requiredSize是分配的实际内存大小,为40

  • requiredAlignmentMask是swift中的字节对齐方式,这个和OC中是一样的,必须是8的倍数,不足的会自动补齐,目的是以空间换时间,来提高内存操作效率

swift_allocObject 源码分析

swift_allocObject的源码如下,主要有以下几部分

  • 通过swift_slowAlloc分配内存࿰

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值