Swift -02:值类型-引用类型

1.延迟存储属性

class Teacher {
    lazy var age:Int = 10
}

1.用lazy修饰的存储属性

2.延迟存储属性必须有一个默认的初始值

我们不给age赋默认值会报错,惰性属性必须具有初始化程序,如果我们修改为可选 lazy var age:Int?,还是报同样的错误

3.延迟存储属性第一次访问时才会被赋值

let t = Teacher()
t.age = 30
print("end")

我们在第一次访问之前和之后访问t的内存情况


image.png

我们看一下,加lazy和不加lazy,Teacher的大小是不是相同

print(class_getInstanceSize(Teacher.self))

不加lazy的大小是24,加lazy的大小是32
为什么加了lazy之后会增加8个字节呢
看sil代码

swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil 
image.png

我们看到lazy修饰的属性,是一个optional的变量
我们第一次getter方式时


image.png

我们第一次获取属性的值时,Optional的值时none,经过bb2赋值后变成case是some值为10
Optional的值多大呢
我们可以通过下面的命令打印看出

print(MemoryLayout<Optional<Int>>.size)
print(MemoryLayout<Optional<Int>>.stride)

size为9,stride为16,Optional<Int>的尺寸大小,在后面会有详细介绍。stride为16是因为字节对齐。

4.延迟存储属性并不能保证线程安全

image.png

这就导致age被初始化两次

5.延迟存储属性对实例对象大小的影响

如果存储属性时Int,不是延迟存储属性,则占8字节,如果是延迟存储属性则占9字节,9因为不是8的倍数,可能会出现内存对齐分配的内存可能会更大。

2.类型属性

class Teacher {
    static var age:Int = 10
}

1.用static修饰的存储属性

2.类型属性必须有一个默认值

如果不给默认值


image.png

3.类型属性只会被初始化一次

我们还是通过sil看


image.png

类型属性是用单利属性初始化的

3.单利的正确写法

1.OC的单利写法

static OCClass*_ocObject = nil;
+ (instancetype)shareManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _ocObject = [[OCClass alloc] init];
    });
    return _ocObject;
}

2.swift的单利写法

class Teacher {
    static let sharedInstance:Teacher = Teacher()
    private init() {}
}

使用static let创建声明一个实例对象
给当前init添加访问控制权限private

4.结构体的初始化

1.结构体不需要自定义初始化方法

struct  Teacher {
    var age:Int
    var name:String  
}
class Student {
    var age:Int
    var name:String
    
}

在class中会报 Class 'Student' has no initializers,这是因为编译器在结构体中自动帮助我们合成初始化方法,也就意味我们可以直接这样调用

var teach = Teacher(age: 12, name: "Hello")

查看sil代码

struct Teacher {
  @_hasStorage var age: Int { get set }
  @_hasStorage var name: String { get set }
  init(age: Int, name: String)
}

2.如果我们的属性有初始化值,系统会提供不同的默认初始化方法

struct  Teacher {
    var age:Int = 18
    var name:String = "Hello"
}
image.png

3.如果我们自定义初始化方法,系统就不会帮我们生成初始化方法

struct  Teacher {
    var age:Int = 18
    var name:String = "Hello"
    init(age:Int,name:String) {
        self.age = age;
        self.name = name
    }
}
image.png

5.结构体是值类型

1.什么是类型

func test()  {
    var age = 18
    var age2 = age
    age = 30
    age2 = 45
    print("age \(age) age2 \(age2)")
}

在age = 30打断点和print处打断点查看内存情况


image.png

直接修改地址内的值18(0x12)-->30(0x1e) 18(0x12)--->45(0x2d)
用withUnsafeMutablePointer(to: &age){print(&0)}查看指针地址
1.值类型,地址中存储的是值
2.值类型传递的过程是传递的副本

6.mutating和inout

mutating

如果我们定义一个stack,类型为struct,

struct MyStack {
    var items = [Int]()
    func push(_ item:Int)  {
        items.append(item)
    }
    
}

报错 Cannot use mutating member on immutable value: 'self' is immutable
我们暂且修改代码

struct MyStack {
    var items = [Int]()
    func push(_ item:Int)  {
        print("end")

    }
    
}

查看sil


image.png

在push中我们只所以能够访问 items,是因为push内有一个默认的参数self,但是我们现在看到self是let,因为MyStack是值类型,let修饰后就不能改变MyStack的值了,所以在上面的items.append(item)就会报错,我们怎么解决这个问题呢?
用mutating修饰

struct MyStack {
    var items = [Int]()
   mutating func push(_ item:Int)  {
    items.append(item)
    }
}

查看sil经过mutabting修饰之后默认参数self就是var类型的


image.png

mutabting的实质是让函数的参数增加inout修饰

2. inout

func swapTwoNumber(a:Int,b: Int)  {
    let  temp = a
    a = b
    b = temp
}

这种写法报错 Cannot assign to value: 'a' is a 'let' constant
函数中参数默认是let类型,我们无法进行修改


image.png

如果我们想修改默认传入的参数,我们使用inout进行修饰

func swapTwoNumber(a:inout Int,b: Int)  {
}

我们看sil,看inout做了什么


image.png

经过inout修饰的是地址取值,并用var修饰。而没用inout修饰的,简单的复制并且是let类型

7.结构体方法调用

结构体中的方法调度是静态调度(编译,链接完成之后当前的函数地址就已经确定存放在了代码段)
1.查看当前mach文件的符号表

nm   mach文件路径
image.png

2.还原符号

xcrun swift-demangle  s13SwiftProperty9MyTeacherV7teacheryyF
image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容