一·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
}
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