版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.07.28 |
前言
??我是swift2.0的時候開始接觸的,記得那時候還不是很穩定,公司的項目也都是用oc做的,并不對swift很重視,我自己學了一段時間,到現在swift3.0+已經出來了,自己平時也不寫,忘記的也差不多了,正好項目這段時間已經上線了,不是很忙,我就可以每天總結一點了,希望對自己對大家有所幫助。在總結的時候我會對比oc進行說明,有代碼的我會給出相關比對代碼。
1. swift簡單總結(一)—— 數據簡單值和類型轉換
2. swift簡單總結(二)—— 簡單值和控制流
3. swift簡單總結(三)—— 循環控制和函數
4. swift簡單總結(四)—— 函數和類
5. swift簡單總結(五)—— 枚舉和結構體
6. swift簡單總結(六)—— 協議擴展與泛型
7. swift簡單總結(七)—— 數據類型
8. swift簡單總結(八)—— 別名、布爾值與元組
9. swift簡單總結(九)—— 可選值和斷言
10. swift簡單總結(十)—— 運算符
11. swift簡單總結(十一)—— 字符串和字符
12. swift簡單總結(十二)—— 集合類型之數組
13. swift簡單總結(十三)—— 集合類型之字典
14. swift簡單總結(十四)—— 控制流
15. swift簡單總結(十五)—— 控制轉移語句
16. swift簡單總結(十六)—— 函數
17. swift簡單總結(十七)—— 閉包(Closures)
18. swift簡單總結(十八)—— 枚舉
類和結構體
??類和結構體是人們構建代碼所用的一種通用且靈活的構造體。與其他編程語言不同的是,swift
并不要求你為自定義類和結構體去創建獨立的接口和實現文件,你需要做的就是在一個單一文件中定義一個類或者結構體,系統將會自動生成面向其他代碼的外部接口。
下面將從下面幾個方向進行講述
- 類和結構體對比
- 結構體和枚舉是值類型
- 類是引用類型
- 類和結構體的選擇
- 集合
collection
類型的賦值和復制行為
類和結構體對比
1. 類和結構體的對比
swift
中類和結構體有很多共同點,主要是:
- 定義屬性用于存儲值
- 定義方法用于提供功能
- 定義附屬腳本用于訪問值
- 定義構造器用于生成初始化值
- 通過擴展以增加默認實現的功能
- 符合協議以對某類提供標準功能
與結構體相比,類還有如下的功能:
- 繼承允許一個類繼承另一個類的特征
- 類型轉換允許在運行時檢查和解釋一個類實例的類型
- 解構器允許一個類實例釋放任何其所被分配的資源
- 引用計數允許對一個類的多次引用
注意:結構體總是通過被復制的方式在代碼中傳遞,因此,請不要使用引用計數。
2. 定義
??下面我們看一下類和結構體是如何定義的,習慣上類名和結構體名是以大寫字母開頭,屬性和方法是以小寫字母開頭,這復合swift
的習慣。
下面看一下具體的定義。
class SomeClass {
//class definition goes here
}
struct SomeStruct {
//structure definition goes here
}
下面我們接著看定義實例。
struct Resolution {
var width = 0
var height = 0
}
class VideoMode{
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name : String?
}
3. 類和結構體實例
??可以用下邊方式進行實例化,結構體和類都使用構造器語法來生成新的實例,構造器語法的最簡單形式是在結構體或者類的類型名稱后跟隨一個空括號。
let someResolution = Resolution()
let someVideoMode = VideoMode()
4. 屬性訪問
??可以使用點語法,你可以訪問實例中所包含的屬性,語法規則是:實例名稱緊跟屬性名。
let someResolution = Resolution()
let someVideoMode = VideoMode()
print(someResolution.width)
print(someVideoMode.resolution.width)
你可以使用點語法為屬性變量賦值。
someVideoMode.resolution.width = 100
??大家可以看點,swift
允許使用點語法直接給一個屬性賦值,這個比OC
要靈活的多了,大家估計還記得OC
中frame
,不可以直接改變其中的成員,要找一個中間變量,改變中間變量的成員,修改以后在賦值回去才可以。這一點swift
要靈活的多了。
5. 結構體類型的成員逐一構造器 - Memberwise Initializers for structure Types
??所有結構體都有一個自動生成的成員逐一構造器,用于初始化新結構體實例中成員的屬性,新實例中各個屬性的初始值可以通過屬性的名稱傳遞到成員逐一構造器中,下面看代碼。
let resolution = Resolution(width: 1920, height: 1080)
與結構體不同,類實例沒有默認的成員逐一構造器。
結構體和枚舉是值類型
??值類型被賦予給一個變量,常數或者本身被傳遞給一個函數的時候,實際上操作的是其的拷貝。其實,在swift
中,所有基本類型:整數、浮點數、布爾值、字符值、數組和字典,都是值類型,并且都是以結構體的形式在后臺所實現。在swift
中,所有的結構體和枚舉都是值類型,這意味著他們的實例,以及實例中所包含的任何值類型屬性,在代碼中傳遞的時候都會被復制。
let resolution = Resolution(width: 1920, height: 1080)
var cinema = resolution
??在上面的例子中,聲明一個常量resolution
并給一個初始值,然后又定義了名字為cinema
的變量,其值為之前聲明的resolution
,因為Resolution
是一個結構體,所以cinema
的值其實是resolution
的一個拷貝副本,而不是resolution
本身,盡管resolution
和cinema
有著相同的寬和高,但是在后臺中,它們是兩個完全不同的實例。
下面看這個例子
class JJSwiftVC: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
let resolution = Resolution(width: 1920, height: 1080)
var cinema = resolution
cinema.width = 2080
print("cinema = \(cinema)")
print("resolution = \(resolution)")
}
}
下面看輸出結果
cinema = Resolution(width: 2080, height: 1080)
resolution = Resolution(width: 1920, height: 1080)
??進一步證明了結構體是值類型,在將resolution
賦值給cinema
的時候,實際上是將resolution
中所存儲的值進行拷貝,然后將拷貝的數據存儲到新的cinema
中,結果是兩個完全獨立的實例碰巧包含有相同的數值。修改其中一個的值,不會影響另外一個的值。
枚舉也遵循相同的準則
class JJSwiftVC: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
var currentDirection = CompassPort.West
let lastDirection = currentDirection
currentDirection = .East
if lastDirection == .West {
print("The remember direction is still .West")
}
else {
print("The remember direction is still .East")
}
}
}
下面看輸出結果
The remember direction is still .West
說明枚舉也是值類型。
類是引用類型
??與值類型不同,引用類型在被賦予到一個變量、常量或者被傳遞到一個函數時,操作的是引用,并不是拷貝,因此,引用的是已知存在的實例本身而不是拷貝。
class JJSwiftVC: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
let resolution = Resolution()
let mode = VideoMode()
mode.resolution = resolution
mode.interlaced = false
mode.name = "10086"
mode.frameRate = 25.0
let nextMode = mode
nextMode.frameRate = 30.0
print(mode.frameRate)
print(nextMode.frameRate)
}
}
下面看輸出結果
30.0
30.0
??可見,類是引用類型。還需要注意的是mode
和nextMode
被聲明為常量,而不是變量,然而你依然可以更改里面的frameRate
,因為這兩個常量本身不會改變,它們并不存儲這個nextMode
實例,在后臺僅僅是對nextMode
的引用,所以,改變的是被引用的基礎nextMode
的frameRate
參數,而不改變常量的值。
1. 恒等運算符
??因為類是引用類型,有可能有多個常量和變量在后臺同時引用某一個類實例,如果能夠判斷兩個常量或者變量是否引用同一個類實例將會很有幫助,為了這個目的,swift
內建了兩個恒等運算。
- 等價于
(===)
- 不等價于
(!==)
看下面這個例子。
class JJSwiftVC: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
let resolution = Resolution()
let mode = VideoMode()
mode.resolution = resolution
mode.interlaced = false
mode.name = "10086"
mode.frameRate = 25.0
let nextMode = mode
nextMode.frameRate = 30.0
print(mode.frameRate)
print(nextMode.frameRate)
if mode === nextMode {
print("They are the same instance !")
}
else {
print("They are not the same instance !")
}
}
}
下面看輸出結果
30.0
30.0
They are the same instance !
這里還要注意===
和==
的不同:
-
===
表示兩個類類型的常量或者變量是否引用同一個類實例。 -
==
表示兩個實例的值相等或者相同。
2. 指針
??對于C
和OC
,你知道使用指針來引用內存中的地址,一個swift
常量或者變量引用一個引用類型的實例與C
語言中的指針類似,不同的是并不直接指向內存中的某個地址,而且也不要求你使用星號*來表明你在創見意一個引用,swift
中這些引用于其他的常量或者變量的定義方式相同。
類和結構體的選擇
??在選擇之前要記住,結構體是值類型,類是引用類型,按照通用標準,當符合下面的條件時,請考慮結構體。
- 結構體的主要目的是用來封裝少量相關簡單數據值。
- 有理由預計一個結構體實例在賦值或傳遞時,封裝的數據將會被拷貝而不是被引用。
- 任何在結構體中存儲的值類型屬性,也將會被拷貝,而不是被引用。
- 結構體不需要去繼承另一個已存在類型的屬性或者行為。
簡單舉幾個適合結構體的例子。
- 幾何形狀的大小
- 一定范圍內的路徑
- 三維坐標系內一點
在所有其他案例匯中,基本都是定義一個類,生成一個它的實例。
集合類型的賦值和拷貝行為
??swift
中的字符串String
、數組Array
和字典Dictionary
類型均以結構體的形式實現,這意味著,String
、Array
、Dictionary
類型的數據被賦值給新的變量或者常量,或者被傳入函數方法中,它們的值會發生拷貝行為(值傳遞方式)。
??而在OC
中字符串NSString
、數組NSArray
和字典NSDictionary
類型均以類的形式出現,這與swift
中以值傳遞的方式是不同的,字符串NSString
、數組NSArray
和字典NSDictionary
在發生賦值或者傳入函數方法中時,不會發生值拷貝,而是傳遞已存在實例的引用。
注意:實際上,在你的代碼中,數組字典字符串的拷貝好像確實是在有拷貝行為的地方產生過,然而,在swift
后臺中,只有確有必要,actural實際
拷貝才會被執行,swift
管理拷貝以確保最優化的性能,所以你也沒有必要去避免賦值以保證最優性能,實際賦值由系統管理優化。
后記
未完,待續~~~