說到結構體和類,還是那句話,只要是接觸過編程的小伙伴們對這兩者並不陌生。但在Swift中的Struct和Class也有着令人眼前一亮的特性。Struct的功能變得更為強大,Class變的更為靈活。Struct中不僅可以定義屬性,並且還可以在其中定義函數,這一點比較像Class的特性了。不過Struct畢竟是結構體,它還是不支持繼承等類特有的屬性的。今天這篇博客就正兒八經的來搞一搞Swift中的Struct和Class。
當然,這篇博客是比較基礎的,但是基礎的東西才是重要的東西呢,廢話不多說了,走起。
一. Struct (結構體)
結構體,說白了就是一組變量,這些變量有統一的命名。在Swift中,我們不僅可以在Struct中聲明變量並為變量設置默認值,而且可以在Struct中添加相應的函數。接下來我們就要創建一個Point結構體,里邊有兩個屬性x坐標和y坐標,並且x坐標和y坐標的初始值為0。其中還有兩個方法,一個是display方法,負責輸出點的坐標,並且還有一個setPoint方法,這個方法負責設置坐標點。然后我們就要去這個結構體去聲明變量,並且調用其中的方法。
1.結構體類型的定義
使用struct關鍵字來聲明我們的結構體類型,結構體類型的名稱為MyPoint, 其中坐標x, y為變量,其初始值為0。並且為我們的結構體添加了一個setMyPoint()方法和display()方法。
由上面的代碼片段你也許會注意到在setMyPoint()方法關鍵字func前邊多了一個mutating關鍵字。在Struct中的函數,默認(不添加mutating關鍵字)的函數對Struct中屬性只有只讀權限。如果你添加上mutating, 那么該函數就對屬性持有讀寫的權限。
2.結構體類型變量的聲明以及結構體函數的使用
接下來我們就利用上述“MyPoint”結構體類型來創建一個結構體類型變量。因為(x, y)值是有初始值的,所以在初始化結構體變量時不需要為其指定初始值。Struct類型的使用和Class使用是大同小異的。MyPoint()就類似於類的構造函數。我們聲明完變量,並分配內存空間后,我們對x, y的值進行打印可以看到x, y的初始值為0。具體如下所示:
我們可以調用訪問權限為讀寫的setMyPoint()方法來改變結構體變量中屬性的值,下方就是把坐標(10.0,20.0)賦值給myPoint變量,具體如下所示。
除了上述方法給結構體變量中的屬性賦值外,我們還可以通過構造函數給其屬性賦值。也就是在給變量分配內存空間時為其指定初始值,這一點就和類的構造函數即為相似了。具體方式如下圖片中的代碼片段所示:
結構體就先聊到這兒,下面開始比較重要的部分:類(Class)
二. 類(Class)
Swift作為一門現代面向對象編程語言,怎么能沒有類呢。關於Objc中的Class, 請參考我之前發表的一篇博客《在Objective-C中淺談面向對象》, 其中淺談了Objective-C中面向對象的東西。今天就聊聊Swift中的類,雖然語言不通,但是Class還是大同小異的。本篇博客的此部分注重Swift類中的語法已經使用方式,對面向對象的思想沒有做過多的陳述,因為我們的重點是在Swift編程,而不是面向對象編程。好~進入這一部分的主題。
1. 類的創建與構造器
為了簡單也是秉着由淺入深的原則,接下來將把上面MyPoint結構體類型使用類的形式來實現一下。簡單從語法上看兩者是大同小異的。下方截圖中的代碼段是在上述MyPoint結構體修改而來的。改成下方MyPoint類做了兩點修改,第一點就是把struct關鍵字改成class關鍵字,
下方是MyPoint類的使用方法,雖然在上述類中沒有構造函數,會自動生成一個默認的無參構造函數。如下所示,調用的就是默認的無參構造函數進行的類的實例化。因為在類定義時我們為類中的屬性(即類的特征)指定了初始值,所以將值進行打印就會顯示初始值了。
你在類定義時,沒有為其定義其他的構造函數,如果你調用了該未定義的構造函數,那么就是你的不對了,編譯器就會報錯了,如下所示:
接下來我們就要為我們的MyPoint()類創建構造函數了。與其他現代編程語言(如C++, C#,Java等)不同,Swift的構造函數不是與類名同名的函數,而是使用特定的函數名init()來創建其構造函數。下方就是我們MyPoint類的構造函數,函數名當然是init了。在構造函數的形參列表中,我們可以為形參指定默認值,雖然下方只是一個構造函數,但是該構造函數與他的形參列表中的默認值一組合起來,可謂是打了一個漂亮的組合拳,使用起來也是灰常順手的。
給構造函數的形參列表指定默認值就省去了重載構造函數的麻煩。上面添加了一個構造函數,並為各個形參指定默認值,下方是其不同的調用方式,這在C++中應該重載4個構造函數才能實現的效果。Swift語言由此可見一斑呢~為之又眼前一亮,心中為之一振呢。具體調用方式如下:
2.對象的賦值與比較
在Swift中也是允許把一個類的變量的值通過賦值運算符(=)來賦值給另一個變量的。不過有一點要搞明白,如果類變量a的值賦值被類變量b,那么變量a和b就指向同一塊內存區域。如果a中的實例變量中的值進行了修改,那么實例b中的值也會進行修改。為了更好的表達這個思想,我們還是來張原理圖來介紹一下對象的賦值吧。具體的原理圖如下所示:
上面是原理,下方就是驗證。我們就聲明兩個變量a, b。 給a分配一個實例的空間,然后把a賦值給b。再接着就是改變a的值,觀察b中的屬性變化。具體如下所示:
如果要判斷兩個變量是否指向同一個實例,那么我們就需要使用恆等運算符(===)了。下方就是判斷a是否和b指向同一個內存空間,具體代碼如下所示:
3.屬性的懶加載(lazy)
在Swift的類中在對類進行初始化時,要對一些屬性進行初始化。如果某些屬性的初始化如果非常的耗費時間,那么在這種情況下我們就可以該初始化耗時的屬性聲明為懶加載的屬性。就是在該屬性聲明的時候加上lazy關鍵字。被Lazy關鍵字修飾的變量會在使用時才會進行空間的分配。下方就是一個lazy的實例。
在下方實例中,除了MyPoint類,我們還需要定義一個MyCycle類。在MyCycle類中,使用到MyPoint類。在MyCycle類中的MyPoint屬性為懶加載屬性,具體請看代碼,如下所示:
(1) 定義MyCycle類,在MyCycle類中,定義一個屬性為lazy的MyPoint類變量。如下所示:
(2)接下來就是使用MyCycle, 聲明MyCycle類型的變量,並為其分配MyCycle的類型實例。由下方實例可知,在調用MyCycle()構造函數時,MyCycle類中的point屬性並沒有對其進行初始化,此刻的point為nil。這樣就減少了MyCycle初始化的時間。
(3) lazy屬性point會在MyCycle實例對象在使用point屬性時才會對其進行初始化,下方是myCycle實例變量調用point屬性的代碼片段,這時就明確的看到point是不為nil的。如下所示:
4. 計算屬性(Count Property)
計算屬性這一個特性在Objective-C中也是沒有的。什么是計算屬性呢,一句話概括:計算屬性的值可以由其他屬性的值來計算得到,同時在給計算屬性賦值時也可以用來計算其他屬性的值。也許說起來比較拗口,理解起來也許回有些困難,那么接下來來個小實例即可明白計算屬性是怎么回事了。
下方我們創建一個名為Money的類,在Money類中有兩個屬性,一個是存儲屬性(普通屬性)名為CNY(代表着人民幣), 另一個是名為USD的計算屬性(代表美元)。在USD計算屬性的set方法中由USD的值計算CNY的值,在USD計算屬性的get方法中由CNY計算出USD的值,並返回。Money類的具體代碼片段如下所示:
計算屬性在使用時和存儲屬性沒有什么區別,下方是Money實例來調用其存儲屬性和計算屬性的代碼段,已經結果輸出如下所示。下方代碼段雖然簡單,但是你慢慢的去品還是很有味道的。先看第一部分,也就是第一次給USD賦值,當給USD賦值時,CNY的之會立即被計算出來。 而當我們給CNY賦值時,USD的值不會被立即計算出來,因為只有在使用USD時才會調用get方法,這時候才會根據CNY的值來計算USD的值。具體結果請看下方代碼段:
5. 屬性觀察
屬性觀察是用來干嘛的呢?說白了,屬性觀測器就是來觀察屬性的賦值情況的,屬性觀測器包括willSet()和didSet , willSet在屬性將要被賦值的時候被調用, didSet是在屬性被賦值后調用,關於這兩個屬性觀察函數,寫個實例就一目了然了。由下方實例可知,在willSet調用時,property屬性的值還為默認值,但是在didSet執行時,property的值已經成為被賦予的值了。
6. 實例方法與類方法
在Objc中,類方法是由+來修飾的,實例方法是由-號來修飾的。在Swift的方法中就沒有+或者-號進行修飾了,但是Swift中聲明方法時,多了一個class。普通方法沒有什么特別之處,而類方法的聲明和定義需要在關鍵字func前添加class關鍵字。下方MyTestClass中定義了一個實例方法和一個類方法,並且給出了調用方式,如下所示:
今天博客的內容就先到這兒,下篇博客會涉及一些類的繼承和類中的方法和屬性的訪問權限等其他一些關於類的東西。