類和結(jié)構(gòu)體是構(gòu)建代碼所用的一種通用的構(gòu)造體。都是可以使用完全相同的語法規(guī)則為類和結(jié)構(gòu)體定義屬性(常量期犬、變量)河哑、添加方法,從而擴展類和結(jié)構(gòu)體的功能龟虎。
注意: 通常一個
類
的實例稱之為對象
璃谨。但在swift中,類和結(jié)構(gòu)體的關(guān)系要比在其他語言中更加的密切鲤妥。為此佳吞,更多是使用實例
而不是對象。
類和結(jié)構(gòu)體的共同之處:
- 定義屬性用于存儲值棉安;
- 定義方法用于提供功能底扳;
- 定義附屬腳本用于訪問值;
- 定義構(gòu)造器用于生成初始化值垂券;
- 通過擴展以增加默認實現(xiàn)的功能花盐;
- 實現(xiàn)協(xié)議以提供某種標準功能;
(注: 后續(xù)章節(jié)會講到屬性
菇爪、方法
算芯、下標腳本
、構(gòu)造過程
凳宙、擴展
熙揍、協(xié)議
)
與結(jié)構(gòu)體相比,類附加以下功能:
- 一個類允許繼承另外一個雷的特征氏涩;
- 類型轉(zhuǎn)換允許在運行時檢查和解釋一個類實例的類型届囚;
- 析構(gòu)器允許一個類實例釋放任何其所分配的資源;
- 引用計數(shù)允許對一個類的多次引用是尖;
注意: 結(jié)構(gòu)體總是通過復(fù)制的方式在代碼中傳遞意系,不適用引用計數(shù)。
一饺汹、類和結(jié)構(gòu)體基本使用
- 定義語法蛔添。類和結(jié)構(gòu)體定義方式類似,通過關(guān)鍵字
class
表示類,通過關(guān)鍵字struct
表示結(jié)構(gòu)體迎瞧,并在大括號中定義具體內(nèi)容:
// 貓的類
class CatClass {
// 名字屬性夸溶,可選類型
var name:String?
// 顏色屬性
var color:UIColor?
}
// 屏幕的結(jié)構(gòu)體
struct Screen {
// 屏幕寬度屬性
var w = 0
// 屏幕高度屬性
var h = 0
}
- 類和結(jié)構(gòu)體的實例,類和結(jié)構(gòu)體實例類似凶硅。結(jié)構(gòu)體和類都使用構(gòu)造器語法來生成新的實例缝裁,構(gòu)造器語法的最簡單方式是在類或結(jié)構(gòu)體類型名后面跟隨一對空括號即可,而這種方式創(chuàng)建的類或結(jié)構(gòu)體實例足绅,其屬性都會初始化為默認值:
// 類的實例
let xiaomiao = CatClass()
// 結(jié)構(gòu)體的實例
var myScreen = Screen()
- 屬性訪問捷绑,使用點語法。規(guī)則是编检,實例名后面跟隨屬性名胎食,兩者通過點
.
連接:
// 類實例
let xiaomiao = CatClass()
xiaomiao.name = "xiaomiao"
xiaomiao.color = UIColor.whiteColor()
// 結(jié)構(gòu)體實例
var myScreen = Screen();
myScreen.w = 320
myScreen.h = 568
- 結(jié)構(gòu)體類型的成員逐一構(gòu)造器,所有結(jié)構(gòu)體都有一個自動生成的成員逐一構(gòu)造器允懂,用于初始化結(jié)構(gòu)體實例中的成員屬性:
var myScreen = Screen(w:320, h:400);
注: 與結(jié)構(gòu)體不同厕怜,類實例沒有默認的成員逐一構(gòu)造器。
二蕾总、結(jié)構(gòu)體和枚舉是值類型
值類型被賦予給一個變量粥航、常量或者被傳遞給一個函數(shù)時,其值會被拷貝生百。在swift中递雀,所有的基本類型:整形、浮點數(shù)蚀浆、布爾值缀程、字符串、數(shù)組市俊、字典杨凑,都是屬于值類型,并且在底層都是以結(jié)構(gòu)體的形式實現(xiàn)摆昧。
?在swift中撩满,所有的結(jié)構(gòu)體和枚舉類型都是值類型,意味著它們的實例绅你,以及實例中所包含的任何類型屬性伺帘,在代碼中傳遞的時候都會被復(fù)制。
// 屏幕結(jié)構(gòu)體
struct Screen {
var w = 0
var h = 0
}
// 實例結(jié)構(gòu)體
var myScreen1 = Screen(w:320, h:568);
// 賦值忌锯,結(jié)構(gòu)體是值傳遞類型伪嫁,即復(fù)制一份
var myScreen2 = myScreen1;
// 修改myScreen2,但myScreen1中是沒有任何影響的
myScreen2.h = 400;
// 實際myScreen1和myScreen2都是完全不同的實例
輸出結(jié)果:
print("myScreen1 --- w:\(myScreen1.w) h:\(myScreen1.h)");
print("myScreen2 --- w:\(myScreen2.w) h:\(myScreen2.h)");
三偶垮、類是引用類型
與值類型不同张咳,引用類型在賦予到一個變量驹吮、常量或被傳遞到一個函數(shù)時,其值不會被拷貝晶伦。因為引用操作的都是已存在的實例本身。
// 定義貓類
class CatClass {
var name:String?
var color:UIColor?
}
// 貓咪多多
let duoduo = CatClass();
duoduo.name = "多多";
duoduo.color = UIColor.whiteColor();
// 賦值啄枕,cat其實表示就是duoduo這個對象本身
let cat = duoduo;
// 修改名字
cat.name = "貓星人-多多";
print("duoduo名字:\(duoduo.name)");
print("cat名字:\(cat.name)");
輸出結(jié)果:
duoduo名字:貓星人-多多
cat名字:貓星人-多多
類是引用類型婚陪,所以在上面例子中
duoduo
和cat
是引用同一個CatClass
實例,即是同一個實例频祝,不同名字泌参。
另外,聲明的時候使用let
常空,依舊可以改變cat.name
沽一。因為duoduo
和cat
這兩個常量的值為改變,只是改變它們引用實例中的name
屬性而已漓糙。
- 等價于(
===
)和不等價于(!==
)铣缠,當(dāng)你要判斷兩個常量或者變量是否引用同一個類實例的時候進行使用:
// 判斷duoduo和cat是否引用同一個實例
if duo duo === cat {
print("引用的是同一個實例");
}
注意: 等價于(用三個等號表示
===
)與等于(用兩個等號表示==
)不同:
"等價于"表示兩個類型的常量或變量引用同一個類實例;
"等于"表示兩個實例的值"相等"或"相同"昆禽;
四蝗蛙、類和結(jié)構(gòu)體的選擇
類和結(jié)構(gòu)體都可以用來自定義數(shù)據(jù)類型,但結(jié)構(gòu)體實例總是通過值傳遞醉鳖,類實例總是通過引用傳遞捡硅。
?考慮使用結(jié)構(gòu)體:
- 該數(shù)據(jù)結(jié)構(gòu)的主要目的是用來封裝少量相關(guān)簡單數(shù)據(jù);
- 預(yù)計該數(shù)據(jù)結(jié)構(gòu)的實例在賦值或傳遞時盗棵,封裝的數(shù)據(jù)將會被拷貝而不是被引用壮韭;
- 該數(shù)據(jù)結(jié)構(gòu)中存儲的值類型,也應(yīng)該被拷貝纹因,而不是被引用喷屋;
- 該數(shù)據(jù)結(jié)構(gòu)體不需要去繼承另一個既有類型的屬性或行為;
其他情況下辐怕,定義一個類逼蒙,生成一個它的實例,并通過引用來管理和傳遞寄疏。實際中是牢,意味著絕大部分的自定義數(shù)據(jù)構(gòu)造都應(yīng)該是內(nèi),而不是結(jié)構(gòu)體陕截。
五驳棱、字符串、數(shù)組农曲、字典類型的賦值與復(fù)制行為
在swift中社搅,許多基本類型驻债,例如String、Array形葬、Dictionary類型都是以結(jié)構(gòu)體的形式實現(xiàn)合呐。即意味著被賦值或作為參數(shù)傳遞時,它們的值會被拷貝笙以。
?Objective-C中NSString淌实、NSArray、NSDictionaty類型都是類的形式實現(xiàn)猖腕,而不是結(jié)構(gòu)體拆祈。即意味著被賦值或作為參數(shù)傳遞時,不會發(fā)生值拷貝倘感,而是傳遞現(xiàn)有實例的引用放坏。
注意: 以上是字符串、數(shù)組老玛、字典的"拷貝"行為的淤年,即是拷貝行為看似總會發(fā)生。但swift中逻炊,指在絕對必要時才執(zhí)行實際的拷貝互亮。swift管理所有的值拷貝確保性能最優(yōu)化,所以我們不必去回避賦值來確保性能最優(yōu)化余素。