Swift學習(七):結構體、類與枚舉的異同(初始化器,值類型,引用類型)

結構體

  • 在 Swift 標準庫中,絕大多數的公開類型都是結構體,而枚舉和類只佔很小一部分 
  • 比如Bool、Int、Double、 String、Array、Dictionary等常見類型都是結構體

 

  • 在第6行調用的,可以傳入所有成員值,用以初始化所有成員(存儲屬性,Stored Property)

結構體的初始化器

編譯器會根據情況,可能會爲結構體生成多個初始化器,宗旨是:保證所有成員都有初始值

  

上面的Point在聲明時沒有爲先x, y初始化值,p1給x和y賦值了,p2,p3,p4沒有爲x,y賦全值

 x有初始化值,y沒有初始化值

y有初始化值,x沒有初始化值

  x,y都有初始化值

  • 下面的代碼能編譯通過嗎?

 因爲可選項都有個默認值nil,因此可以編譯通過


結構體的初始化器

  • 一旦在定義結構體時自定義了初始化器,編譯器就不會自動再幫它自動生成其他初始化器

  這時不會默認初始化值,需要傳入,否則報錯

 

  • 以下兩段代碼完全等效

      

  • 結構體的內存結構


  • 類的定義和結構體類似,但編譯器並沒有爲類自動生成可以傳入成員值的初始化器

由上可得:類的屬性一定要有初始化值

  • 如果類的所有成員都在定義的時候指定了初始值,編譯器會爲類生成無參的初始化器,成員的初始化是在這個初始化器中完成的

  • 上面2段代碼是完全等效的

結構體與類的本質區別

結構體是值類型(枚舉也是值類型),類是引用類型(指針類型)

由上可以看出:point也就是結構體存儲在棧空間,size也就是類存儲在堆空間

上圖都是針對64bit環境


值類型

  • 值類型賦值給var、let或者給函數傳參,是直接將所有內容拷貝一份, 類似於對文件進行copy、paste操作,產生了全新的文件副本。屬於深拷貝(deep copy)

 由於是值類型,互不影響,所以p1.x = 10, p1.y = 20


值類型的賦值

   

  • 在Swift標準庫中,爲了提升性能,String、Array、Dictionary、Set採取了Copy On Write的技術 
  • 比如僅當有“寫”操作時,纔會真正執行拷貝操作
  • 對於標準庫值類型的賦值操作,Swift 能確保最佳性能,所有沒必要爲了保證最佳性能來避免賦值
  • Swift標準庫中的結構體爲保持性能,只有在結構體被賦值並且有寫入的時候才進行深拷貝,但是自己定義的結構體,只要結構體有被賦值操作就會深拷貝。
  • 建議:不需要修改的,儘量定義成let


引用類型

  • 引用賦值給var、let或者給函數傳參,是將內存地址拷貝一份
  • 類似於製作一個文件的替身(快捷方式、鏈接),指向的是同一個文件。屬於淺拷貝(shallow copy)

  

 屬於淺拷貝,s1.width = 11, s2.height  = 22


對象的堆空間的申請過程

  •  在Swift中,創建類的實例對象,要向堆空間申請內存,大概流程如下
  • Class.__allocating_init()
  • libswiftCore.dylib:_swift_allocObject_
  • libswiftCore.dylib:swift_slowAlloc
  • libsystem_malloc.dylib:malloc
  • 在Mac、iOS中的malloc函數分配的內存大小總是16的倍數
  • 通過class_getInstanceSize可以得知類的對象真正使用的內存大小

具體解析內存佔用:

import Foundation

func testInstance() {
    class Point {
        //引用類型前面會有16個字節
        var x : Int = 11  //8
        var test = true  //1
        var y : Int = 22 //8
    }
    let p = Point()
    print(class_getInstanceSize(Point.self)) //40
    print(class_getInstanceSize(type(of: p))) //40
    print(Mems.size(ofRef:p)) //48
    //33   類對象真正利用,真正存具體數據的內存空間
    //40   類的對象真正使用的內存大小
    //48   類對象實際分配的內存大小
}

 


引用類型的賦值操作

 


值類型、引用類型的let

   

p表示值類型賦值的內存數據是常量,不可變,也就是10和20不可變,下面對p的三個賦值操作都改變了棧空間的內存數據,所以報錯

s表示引用類型賦值的內存數據是常量,這裏的棧空間存儲的內存數據是指向堆內存空間的地址,第一個屬於重新賦一個新值,指向的內存地址改變,所以報錯,但是後兩個沒有改變指向的堆內存的地址,所以沒有報錯

  


嵌套類型


枚舉、類、結構體都可以定義方法

一般把定義在枚舉、結構體、類內部的函數,叫做方法

枚舉:

類: 

結構體: 

注意;方法不佔用實力對象內存的,方法的本質就是函數,方法實際上是放在代碼段的.

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章