WWDC14 Session 402 學習筆記 (下)

由於上一篇篇幅太長,mou沒事就崩潰,而且太長了也沒人願意仔細看了。我還是把他分開吧。

Class

和Objective-C 不同,Swift的Class,沒有頭文件。

定義:

1
2
3
class nyan{

}

聲明:

1
var a = nyan()

和Struct不同,只要是Class類型,就是Ref,而不是Value,且我們不用管理內存。也就是說:它是自動內存管理的。

初始化:

init關鍵字,和OC一樣。不過這塊非常像CPP,如下面這東西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class nyan{
    var num: Int = 1024
    init()
    {
        num = 1;
    }
}

class miao:nyan
{
    var num1: Int = 1
    init() {
        num1 = 2
    }
}

var a = miao()

println(a.num)
println(a.num1)

如果以oc的思維來看,它輸出的應該是 1024, 2。因為oc只要沒有call super,就是覆蓋掉了。

但實際上Swift輸出的是 1, 2。倘若,我們在兩個init加上打log的話,會發現,子類的init先運行,然後運行父類的。

那麼什麼時候在子類的init裡面call super.init()呢?

顯而易見:當在子類裡面要調用父類的成員變量時,要先調用super.init()去初始化它,若沒有寫的話,XCode會報編譯錯誤。

重載

和C# java一樣,前面要頂著override關鍵字。

Property

Swift 擁有兩種 Property,一個是Stored Property, 另一個是 Computed Property

Stored Property
1
2
3
4
5
6
7
8
9
10
class nyan{
    var num = 3
}

var a = nyan()

println(a.num)
a.num = 1

println(a.num)

由於Class是Ref,所以哪怕我們用 let a = nyan(),我們也可以修改a中的內容。只是我們不能修改 a 指向的地址罷了。

注意,如果我沒理解錯的話:

Class的所有成員變量都是Stored Property,沒有private關鍵字來修飾它的。

Computed Property

顧名思義,Property的值是經過計算而來的。一般常常用在readOnly屬性上,和C#一樣也是用get set關鍵字來做。

1
2
3
4
5
6
7
8
9
10
11
12
13
class nyan{
    var num: Int
    {
  
    get{
        return 1024
    }
    }
}

var a = nyan()

println(a.num)

如果沒有set關鍵字的時候,get{}可以省略:

1
2
3
4
5
6
7
8
9
10
class nyan{
    var num: Int
    {
     return 1024
    }
}

var a = nyan()

println(a.num)

如果我沒有理解錯的話,如果需要set關鍵字的時候,那就一定要一個 Stored Property。因為沒有私有變量…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class nyan{
    var fakePrivateNum: Int = 1024

    var num: Int
    {
    set{
        self.fakePrivateNum = newValue
    }

    get{
        return self.fakePrivateNum
    }
    }
}

var a = nyan()

println(a.num)
a.num = 1

println(a.num)

繼承修改set / get 的時候要注意,這裡和OC還不太一樣。如果我這麼寫了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class nyan{
    var num: Int = 1024
}

class miao:nyan
{
    override var num: Int{
    set{
        num = 2 * newValue
    }
    get{
        return num
    }
    }
}

var a = miao()

println(a.num)
a.num = 1

編譯器會報錯,而且會出現棧溢出,大量遞歸調用在 return 那一步。正確的寫法應該是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class nyan{
    var num: Int = 1024
}

class miao:nyan
{
    override var num: Int{
    set{
        super.num = 2 * newValue
    }
    get{
        return super.num
    }
    }
}

var a = miao()

println(a.num)
a.num = 1

println(a.num)

willSet didSet

如果我們想監視,StoredProperty的修改,可以這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class nyan{
    var num: Int = 1024
    {
    willSet{
        println("newValue: \(newValue)" )
    }
    didSet{
        println("oldValue: \(oldValue)")
    }
    }
}

let a = nyan()
a.num = 1

OOP這面的東西好亂…信息量好大…..寫的也好亂….

Struct

一句話形容它:是一個Value類型的不能繼承的Class。

不過注意兩點:

  1. 雖說不能繼承,但是可以實現接口!
  2. 雖說和class功能一樣,但是他所有method是只讀權限,和cpp的const一樣..如果想要在其中修改struct的member,就要在前面加上 mutating

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct nyan{
    var num: Int = 1

    func changeNum(x:Int)
    {
        if (x>10)
        {
            num += x
        }
    }

    init()
    {
        changeNum(11)
    }
}

這麼寫直接CE, 要在前方加上 mutating

Enumerations

和 C家族的 Enum 不太一樣,和 Java 的比較像。

  • 他可以不包含實際類型,例如:
1
2
3
enum compassPoint{
  case North, South, East, West
}

在調用的時候,可以 var a = compassPoint.West 當a被推斷為 compassPoint 類型的時候,就可以用 a = .East賦值了。

  • 他可以包含多種類型,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
enum TrainStatus{
    case OnTime
    case Delayed(Int)

    init(){ self = OnTime }

    var description: String{
    switch self{
    case OnTime:
        return "On Time"
    case Delayed(let minutes):
        return "delayed by \(minutes) minutes"
        }
    }
}

var status = TrainStatus()
println(status.description)
status = .Delayed(42)
println(status.description)
  • enum 的定義可以內嵌到 class中

Extensions

有點像OC的Category,但是Swift是靜態語言,他不再需要msg_send這樣的方法來調用method,所以,Extension不能做出來Swift類的method Swizzling。但同時可以擴展的東西不侷限在class上了,一切的一切都可以擴展。

例如Int:

1
2
3
4
5
6
7
8
9
10
11
12
13
extension Int
{
    func repetitions(task:()->()) {
        for i in 0..self
        {
            task()
        }
    }
}

500.repetitions(){
    println("Hello")
}

注意:Int也好,String也好。他們雖說是值類型,但是和C的int還不是一個意思。他是值類型的對象,並不是一個值。正是因為這個特性,我們才可以在Int內部call self,給他寫extension。

泛型

不用過多解釋了和其他語言的一樣。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Stack<T>{
    var elements = T[]()

    mutating func push(element: T){
        elements.append(element)
    }

    mutating func pop() -> T {
        return elements.removeLast()
    }
}

var intStack = Stack<Int>()
intStack.push(50)
let lastIn = intStack.pop()

總結

我他媽終於寫完了三篇筆記。短短50分鐘的視頻,信息量太大了。寫第一篇的時候覺得這門語言是個坑,但三篇寫下來覺得。這門語言好他媽優雅。

擁有動態語言的書寫風格,靜態語言的運行速度,現代語言的特性,傳統語言般嚴謹的oop。不過相對的,學習成本高多了。

首先,你要理解oop的繼承,重載,多態,泛型

其次,你要熟悉動態語言的書寫風格,

然後,你要對高級現代工業語言java/c#的特性有所了解,語法看起來非常不同,其實和C#還真的是蠻像的。

最後,你要熟悉OC以及相關庫,畢竟iOS/OSX開發,目前來看離不開OC

總之,這門語言對於新手來說,門檻太高,但是非常優秀。不愧是LLVM的作者寫的語言啊!

Comments