本文源自本人的學習記錄整理與理解封断,其中參考閱讀了部分優(yōu)秀的博客和書籍,盡量以通俗簡單的語句轉述舶担。引用到的地方如有遺漏或未能一一列舉原文出處還望見諒與指出坡疼,另文章內容如有不妥之處還望指教,萬分感謝衣陶。
結構體
Swift標準庫中柄瑰,絕大多數(shù)的公開類型都是結構體,而枚舉和類只占很少一部分剪况,比如:Bool教沾、Int、Double译断、String授翻、Array、Dictionary等常見類型都是結構體
- 開發(fā)者可以自定義結構體
結構體定義
struct Date {
var year: Int
var month: Int
var day: Int
}
使用(利用初始化器初始化Date) 孙咪,可以傳入所有成員值堪唐,用以初始化所有成員(存儲屬性或Stored Property)
var date = Date(year: 2020, month: 5, day: 18 )
- 所有結構體都有一個編譯器自動生成的
初始化器
(initializer、初始化方法翎蹈、構造器淮菠、構造方法) - 在Date(year: 2020, month: 5, day: 18 )調用時,可以傳入所有成員值荤堪,用以初始化所有成員(存儲屬性合陵,Stored Property)
結構體的初始化器
- 在初始化時必須傳入
所有
成員值枢赔,否則就會編譯報錯,前提是成員沒有給初始值
- 編譯器會根據(jù)情況拥知,可能會為結構體生成多個初始化器踏拜;宗旨是:保證所有成員都有初始化值
思考:下面代碼能編譯通過嗎 ?
struct Point {
var x:Int?
var y:Int?
}
var p1 = Point(x:10,y:10)
var p2 = Point(y:10)
var p3 = Point(x:10)
var p4 = Point()
可以編譯通過举庶,可選項都有一個默認值nil; 因此可以編譯通過
自定義初始化器
- 一旦定義結構體時自定義初始化器执隧,編譯器就不會再幫它自動生成其他初始化器
struct Point {
var x:Int?
var y:Int?
//自定義初始化器
init(x:Int, y:Int){
self.x = x
self.y = y
}
}
var p1 = Point(x:10,y:10)
var p2 = Point(y:10)
var p3 = Point(x:10)
var p4 = Point()
窺探初始化器的本質
下面兩段代碼是完全等效的
struct Point {
var x:Int
var y:Int
//自定義初始化器
init(){
x = 0
y = 0
}
}
---------------------------------------------
struct Point {
var x:Int = 0
var y:Int = 0
}
結構體的內存結構
x和y各占8個字節(jié),Bool占一個字節(jié)户侥;內存對齊是8的倍數(shù)镀琉;所以最終Point占24字節(jié)
類
- 類的定義和結構體類似,但編譯器并
沒有
為類自動生成可以傳入成員值得初始化器
類的初始化器
- 如果類的所有成員都在定義的時候指定了初始值蕊唐,編譯器會為類生成無參的初始化器
- 成員的初始化是在這個初始化器中完成的屋摔;所以下面兩段代碼完全等效
class Point {
var x:Int
var y:Int
//自定義初始化器
init(){
x = 0
y = 0
}
}
---------------------------------------------
class Point {
var x:Int = 0
var y:Int = 0
}
結構體和類的本質區(qū)別
- 結構體是
值類型
(枚舉也是值類型),類是引用類型
(指針類型) - 結構體不需要向堆空間申請內存替梨,類需要向堆空間申請內存
對象的對空間申請過程
函數(shù)被定義在類的內部和在外部钓试,都是向棧空間申請內存 副瀑!唯一的區(qū)別就是作用域不同
值類型
- 值類型賦值給var弓熏、let或者給函數(shù)傳參,是直接將所有內容拷貝一份
- 類似于對文件進行copy糠睡、paste操作挽鞠,產生了新的副本;屬于深拷貝(deep copy)
- 值類型的賦值操作
var s1 = "逍遙侯"
var s2 = s1
s2.append("~泰牛了")
print(s1) //輸出結果:逍遙侯
print(s2) //輸出結果:逍遙侯~泰牛了
- 在Swift標準庫中狈孔,為了提升性能信认,String、Array均抽、Dictionary嫁赏、Set采取了
Copy On Write
的技術 ; 也就是說當我們去修改內存時才會有copy操作,只是單純的賦值是不會深拷貝油挥!
注意
:自己定義的結構體是沒有這個操作的 - 比如僅當有”寫“操作時潦蝇,才會真正執(zhí)行拷貝操作
- 對于標準庫類型的賦值操作,Swift能確定最佳性能喘漏,所以沒必要為了保證最佳性能來避免賦值护蝶;建議:不需要修改的,盡量定義成
let
引用類型
- 引用類型賦值給var翩迈、let或者給函數(shù)傳參持灰,是將內存地址拷貝一份
- 類似于制作一個文件的替身(快捷方式、鏈接)负饲,指向的是同一個文件堤魁。屬于
淺拷貝
(shallow copy)
注意:全局變量的內存地址是唯一的