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

1.延遲存儲屬性

class Teacher {
    lazy var age:Int = 10
}

1.用lazy修飾的存儲屬性

2.延遲存儲屬性必須有一個默認(rèn)的初始值

我們不給age賦默認(rèn)值會報錯,惰性屬性必須具有初始化程序,如果我們修改為可選 lazy var age:Int?,還是報同樣的錯誤

3.延遲存儲屬性第一次訪問時才會被賦值

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

我們在第一次訪問之前和之后訪問t的內(nèi)存情況


image.png

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

print(class_getInstanceSize(Teacher.self))

不加lazy的大小是24,加lazy的大小是32
為什么加了lazy之后會增加8個字節(jié)呢
看sil代碼

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

我們看到lazy修飾的屬性,是一個optional的變量
我們第一次getter方式時


image.png

我們第一次獲取屬性的值時,Optional的值時none,經(jīng)過bb2賦值后變成case是some值為10
Optional的值多大呢
我們可以通過下面的命令打印看出

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

size為9,stride為16,Optional<Int>的尺寸大小,在后面會有詳細(xì)介紹。stride為16是因為字節(jié)對齊。

4.延遲存儲屬性并不能保證線程安全

image.png

這就導(dǎo)致age被初始化兩次

5.延遲存儲屬性對實例對象大小的影響

如果存儲屬性時Int,不是延遲存儲屬性,則占8字節(jié),如果是延遲存儲屬性則占9字節(jié),9因為不是8的倍數(shù),可能會出現(xiàn)內(nèi)存對齊分配的內(nèi)存可能會更大。

2.類型屬性

class Teacher {
    static var age:Int = 10
}

1.用static修飾的存儲屬性

2.類型屬性必須有一個默認(rèn)值

如果不給默認(rèn)值


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創(chuàng)建聲明一個實例對象
給當(dāng)前init添加訪問控制權(quán)限private

4.結(jié)構(gòu)體的初始化

1.結(jié)構(gòu)體不需要自定義初始化方法

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

在class中會報 Class 'Student' has no initializers,這是因為編譯器在結(jié)構(gòu)體中自動幫助我們合成初始化方法,也就意味我們可以直接這樣調(diào)用

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.如果我們的屬性有初始化值,系統(tǒng)會提供不同的默認(rèn)初始化方法

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

3.如果我們自定義初始化方法,系統(tǒng)就不會幫我們生成初始化方法

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

5.結(jié)構(gòu)體是值類型

1.什么是類型

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

在age = 30打斷點和print處打斷點查看內(nèi)存情況


image.png

直接修改地址內(nèi)的值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內(nèi)有一個默認(rèn)的參數(shù)self,但是我們現(xiàn)在看到self是let,因為MyStack是值類型,let修飾后就不能改變MyStack的值了,所以在上面的items.append(item)就會報錯,我們怎么解決這個問題呢?
用mutating修飾

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

查看sil經(jīng)過mutabting修飾之后默認(rèn)參數(shù)self就是var類型的


image.png

mutabting的實質(zhì)是讓函數(shù)的參數(shù)增加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
函數(shù)中參數(shù)默認(rèn)是let類型,我們無法進(jìn)行修改


image.png

如果我們想修改默認(rèn)傳入的參數(shù),我們使用inout進(jìn)行修飾

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

我們看sil,看inout做了什么


image.png

經(jīng)過inout修飾的是地址取值,并用var修飾。而沒用inout修飾的,簡單的復(fù)制并且是let類型

7.結(jié)構(gòu)體方法調(diào)用

結(jié)構(gòu)體中的方法調(diào)度是靜態(tài)調(diào)度(編譯,鏈接完成之后當(dāng)前的函數(shù)地址就已經(jīng)確定存放在了代碼段)
1.查看當(dāng)前mach文件的符號表

nm   mach文件路徑
image.png

2.還原符號

xcrun swift-demangle  s13SwiftProperty9MyTeacherV7teacheryyF
image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容