Swift底层-对象&结构&属性

2021-03-08 10:02:35 浏览数 (1)

一·allocating_init()

pushq %rbp //很明显,往下读pushq movl 参数入栈和传递

movq %rsp, %rbp

pushq %r13

pushq %rax

movl $0x28, %esi

movl $0x7, �x

movl %r13, %rdi

callq 0x1000000fd ;symbol stub for: swift_allocObject //为对象开辟内存空间

movq %rax, %r13

callq 0x1000000ed ;Object.instance.init() -> objc.instance at mian.swift //调用init初始化

addq $0x8 , %rsp

popq %r13

popq %rbp

retq //参数出栈,并返回

二·swift-allocObject

Swift

Object-C

初始化对象所需要参数

HeapMetadata,requiredSize,AlignmentMask

instanceSize,calloc,initIsa

相同点

Size & AlignmentMask

Size & align16 & fastallocCacheMask

Size大小

metadata, refCounts 16字节

ISA,cache,bits,superclass 大于32字节

对齐

8字节对齐

16字节对齐

在堆处创建大小空间

malloc

calloc

方法存储位置

metadata()

method_list

三·HeapMetadata

struct{

HeamMeatadata const *metadata;

define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS InlineRefCounts refCounts

}

很明显,swift 有两个常驻成员1.元类数据 指针8字节 2.引用计数,本质上是一个类 也是指针占8字节

相对于OC类的不同可以看我以前写的文章

四·TargetMetadata<Runtime>

有一段注释:The kind .Only valid for non-class metadata; getKind() must be used to get the kind value

Kind是什么?

StoredPointer Kind; 储存指针?

name

value

Class

0x0

Struct

0x200

Enum

0x201

Optional

0x202

ForeignClass

0x203

Opaque

0x300

Tuple

0x301

Function

0x303

Existential

0x303

Metatype

0x304

ObjCClassWrapper

0x305

ExistentialMetatype

0x306

HeapLocalVariable

0x400

HeapGenericLocalVariable

0x500

ErrorObject

0x51

LastEnumerated

0x7FF

五·类结构

继承关系

Metadata::Class ----> TargetMetadata(属性)----> TargetAnyClassMetadata(kind,superclass,cacheData) ---->TargetHeapMeatdata ---->TargetMetadata(kind)

总的来说上面的N重继承为了表达一个东西:

swift_class_t{

void *isa; //isa,kind(unsigned long)

void *superClass

void *cacheData

flags

instanceAddressOffset

instanceSize

instanceAlignMask

reserved

classSize

classAddressOffset

void *description

}

和OC好像,可以看出如果我的Class继承的是NSObject的话,那么kind就是isa

反之,则是普通的swift类,为普通的unsigned lonog kind

六·属性观察者

var name: String = "" {

willSet{ //新值存储之前调用

print("willSet newValue(newValue)")

}

didSet{ //新值存储后,value就变成了old

print("didSet oldValue(oldValue)")

}

}

如何证明的确调用了这两个方法呢?查看sil代码

%0 :String, let , name "value", argno 1

%1 :Test, let, name "self", argno 2

%4 = ret_element_addr %1 :$Test, #Test.name 参数传递

%5 = begin_access [read] [dynamic] %4 : $*Sting 参数出栈,相当于%5=(String *)&name

%6 = load %5 : $*String 存储到%6 oldValue = %5

function_ref name will Set

 = fun_ref : convention(method)

 = apply (%0,%1) 传递两个参数(%0,%1)

retain_value %0 :String retain(newValue)

 = ref_element_addr %1:@convention(method)  = &%1

 = begin_access [modify] [dynamic] : $*String

 = load   = *

store %0 to  :$*String newValue = %0

release_value   = nil

end_access 

func_ref Test.name.didSet

 = func_ref

= (%6,%1) &oldValue =name

属性观察者会在init处调用吗?

答案是不会,在类的初始化的内存结构中

didSet{

print(self.age)

}

init(){

age = 18

}

didSetdidSet

init不会调用属性观察者,如果调用了,那么访问的是上面内存空间的空白处,也就是所谓的野指针,但是这在Swift中是不被允许的,所以print无法打印self.age

观察者对象的访问方法

1.定义的储存属性 var name: Sting = "xx"

2.类继承的存储属性 class T1:T2{override var name:String}

3.继承计算属性 var age:Int{get{age} set{self.age = newValue }} override var age: Int

从中可以看出,override是比set get 方法优先的

七·结构体

·相对于class来说结构体不需要自定义初始化方法,在sil层会调用init

struct Test{

var age: Int

var name: String

}

.sil struct{

@hasStorage var age: Int {get set}

@hasStroage var name: String {get set}

inint(age:Int , name:String)

}

假如结构体初始化变量已经有了初始值,那么就不会调用init方法

·结构体是值类型 静态的

%1 = alloc_stack $Test, let , name "self" %1=struct.self

%2 = interger_literal $Builtin.Int64, 10 %2 = 10

%4 = struct_element_addr %1: $*Test, #age %4 = &struct->age

store %3 to %4 $*Int %4 = (Int *)%3

return  : Test

值类型中,尽量避免包含有引用类型,在传递过程中还是用strong_retain 引用计数来管理的

参数通常是let属性,如果要修改let 则需要添加inout关键字,对于方法来说需要添加mutating

0 人点赞