2014年6月4日 星期三

Swift 那些二三事

Swift 語言概覽

WWDC 昨晚看完後立馬幹了第一件事,把 object-c 丟到垃圾桶讓它回收去

 ok just work to learn Swift language

 丟掉啦,幹




環境 xcode 6.0

創建新 new -> workspace -> 選擇 project 存放位置

Save as name 暫定取名為 learnSwift.xcodespace

創建新的 project -> OS X -> Application -> CommandLine Tool

此時頁面下方 language 可以看到有四種語言 swift object-c c c++
選擇 swift 後,輸入 product name -> helloSwift



此時左方已經創建出兩個 folder,在專案名稱的裡面已經會存在一個 main.swift 檔案
打開檔案後裡面已經預設一行程式碼


import Foundation

println("Hello, world")


按下鍵盤的 command + R 運行,或者左上方的箭頭 run

此時下方的控制台將會輸出 Hello, world 字串

以上可以看到他的架構比 C 簡易許多,甚是也有 Python 風格存在
吸收了 Objective-C 的優點,且更加強大易用,可以使用現有的Cocoa和Cocoa Touch框架,兼具編譯語言的高性能(Performance)和腳本語言的交互性(Interactive)
按照 apple 的風格,Swift用來寫iOS和OS X程序已勢必是未來的趨勢,當然也不會去相容於其他系統

PS 還是乖乖準備要買一台自己 mac....orz ( 請問可以募款集資購買一台嗎,我不是正妹沒有乳溝可以露,所以沒有辦法表示誠意 )

簡易的 helloWorld 已經示範完畢,接下來了解他的變數和常數怎麼應用
其實這裡還看到 js 的影子存在

Swift使用var聲明變量,let聲明常數


var myVariable = 42
myVariable = 50
let myConstant = 42


類型推導

Swift支持 Type Inference,所以上面的程式碼不需指定類型,如果需要指定類型:


let explicitDouble : Double = 70


Swift不支持隱式類型轉換(Implicitly casting),所以下面的程式碼需要顯式類型轉換(Explicitly casting)


let label = "The width is "
let width = 94
let labelWidth = label + String(width)



字符串格式化

Swift使用\(item)的形式進行字符串格式化:


let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."


array 和 dictionary

Swift使用 [] 操作符聲明 array 和 dictionary:


var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"

var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"


一般使用初始化器(initializer)語法宣告空 array 和 dictionary:


let emptyArray = String[]()
let emptyDictionary = Dictionary<String, Float>()


如果類型信息已知,則可以使用 [] 宣告空 array,使用 [:] 聲明空 dictionary


迴圈

Swift 的迴圈語法含 if 和switch,其餘迴圈還有包含 for-in、for、while 和 do-while,循環/判斷條件不需要括號,但循環/ body 必需括號:


let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
        teamScore += 3
    } else {
        teamScore += 1
    }
}


空類型

結合 if 和 let,可以方便的處理可空變量(nullable variable)。對於空值,需要在類型聲明後添加?顯式標明該類型可空。


var optionalString: String? = "Hello"
optionalString == nil

var optionalName: String? = "John Appleseed"
var gretting = "Hello!"
if let name = optionalName {
    gretting = "Hello, \(name)"
}



switch

Swift中的switch支持各種各樣的比較操作:


let vegetable = "red pepper"
switch vegetable {
case "celery":
    let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
    let vegetableComment = "That would make a good tea sandwich."
case let x where x.hasSuffix("pepper"):
    let vegetableComment = "Is it a spicy \(x)?"
default:
    let vegetableComment = "Everything tastes good in soup."
}


for-in除了滾 array 也可以用來 dictionary:


let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
largest



while 迴圈和 do-while 迴圈:


var n = 2
while n < 100 {
    n = n * 2
}
n

var m = 2
do {
    m = m * 2
} while m < 100
m


Swift支持傳統的 for 迴圈,此外也可以通過結合,生成一個區間和 for-in 實現同樣的邏輯。


var firstForLoop = 0
for i in 0..3 {
    firstForLoop += i
}
firstForLoop

var secondForLoop = 0
for var i = 0; i < 3; ++i {
    secondForLoop += 1
}
secondForLoop


函數

Swift使用func關鍵字聲明函數:


func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")



通過元組(Tuple)返回多個值:


func getGasPrices() -> (Double, Double, Double) {
    return (3.59, 3.69, 3.79)
}
getGasPrices()


支持帶有變長參數的函數:


func sumOf(numbers: Int...) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}
sumOf()
sumOf(42, 597, 12)


函數也可以嵌套函數:


func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
returnFifteen()


作為對象,函數既可以作為返回值,也可以作為參數傳遞:


func makeIncrementer() -> (Int -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)



func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, lessThanTen)


Closure 使用

本質來說,函數是特殊 Closure,Swift 中可以利用 {} 宣告匿名Closure:


numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
    })


當 Closure 的類型已知時,可以使用下面的簡化寫法:


numbers.map({ number in 3 * number })


此外還可以通過參數的位置來使用參數,當函數最後一個參數是 Closure 時,可以使用下面的語法:


sort([1, 5, 3, 12, 2]) { $0 > $1 }



class 應用

Swift 創建一個 class 為以下方法:


class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}


宣告 Shape 的方式,並調用其字串和方法。


var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()


通過init 宣告,既可以使用 self 引用成員 name,也可以引用 numberOfSides


class NamedShape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
        self.name = name
    }

    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}


使用deinit進行清理工作。


繼承和 override父類方法

Swift支持繼承和多態(override父類方法):


class Square: NamedShape {
    var sideLength: Double

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }

    func area() -> Double {
        return sideLength * sideLength
    }

    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()


注意:如果這裡的 simpleDescription 方法沒有被標識為 override,則會 compiler 錯誤


屬性

為了簡化代碼,Swift引入了屬性(property),見下面的perimeter字段:


class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
    get {
        return 3.0 * sideLength
    }
    set {
        sideLength = newValue / 3.0
    }
    }

    override func simpleDescription() -> String {
        return "An equilateral triagle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength


注意: setter 中,接收的值被自動命名為newValue

willSet和didSet

EquilateralTriangle 的宣告進行了如下操作:


class TriangleAndSquare {
    var triangle: EquilateralTriangle {
    willSet {
        square.sideLength = newValue.sideLength
    }
    }
    var square: Square {
    willSet {
        triangle.sideLength = newValue.sideLength
    }
    }
    init(size: Double, name: String) {
        square = Square(sideLength: size, name: name)
        triangle = EquilateralTriangle(sideLength: size, name: name)
    }
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
triangleAndSquare.square.sideLength
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
triangleAndSquare.triangle.sideLength


從而保證 triangle 和 square 擁有相等的 sideLength。

調用方法

Swift 中,函數的參數名稱只能在函數內部使用,但方法的參數名稱除了在內部使用外還可以在外部使用(第一個參數除外),例如:


class Counter {
    var count: Int = 0
    func incrementBy(amount: Int, numberOfTimes times: Int) {
        count += amount * times
    }
}
var counter = Counter()
counter.incrementBy(2, numberOfTimes: 7)


注意 Swift 支持為方法參數取別名:在上面的代碼裡,numberOfTimes 向外部,times 向內部。

? 的另一種用途

使用可空值時,? 可以出現在方法、屬性或下標前面。
如果 ? 前的值為 nil,那麼 ? 後面的表達式會被忽略,而原表達式直接返回 nil,例如:


let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional
square")
let sideLength = optionalSquare?.sideLength


當 optionalSquare 為 nil 時,sideLength 屬性調用會被忽略。

enum 應用

使用enum創建枚舉——注意 Swift 的 enum 可以關聯方法:


enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
        func simpleDescription() -> String {
        switch self {
            case .Ace:
                return "ace"
            case .Jack:
                return "jack"
            case .Queen:
                return "queen"
            case .King:
                return "king"
            default:
                return String(self.toRaw())
        }
    }
}
let ace = Rank.Ace
let aceRawValue = ace.toRaw()


使用 toRaw 和 fromRaw 在原始(raw)數值和 enum 之間進行轉換:


if let convertedRank = Rank.fromRaw(3) {
    let threeDescription = convertedRank.simpleDescription()
}


注意枚舉中的成員值(member value)是實際的值(actual value),和原始值(raw value)沒有必然關聯。

一些情況下枚舉不存在有意義的原始值,這時可以直接忽略原始值:


enum Suit {
    case Spades, Hearts, Diamonds, Clubs
        func simpleDescription() -> String {
        switch self {
            case .Spades:
                return "spades"
            case .Hearts:
                return "hearts"
            case .Diamonds:
                return "diamonds"
            case .Clubs:
                return "clubs"
        }
    }
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()


除了可以關聯方法,enum 還支持在其成員上關聯值,同一 enum 的不同成員可以有不同的關聯的值:


enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
    case let .Result(sunrise, sunset):
        let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
    case let .Error(error):
        let serverResponse = "Failure... \(error)"
}



結構 struct

Swift使用 struct 關鍵字創建結構。結構支持構造器和方法這些類的特性。結構和類的最大區別在於:結構的實例按值傳遞(passed by value),而類的實例按引用傳遞(passed by reference)。


struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()


協議(protocol)和擴展(extension)

協議

Swift 使用 protocol 定義協議:


protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}


類型、enum 和結構都可以實現(adopt)協議


class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += " Now 100% adjusted."
    }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription


擴展

擴展用於在已有的類型上增加新的功能(比如新的方法或屬性),Swift 使用 extension 宣告擴展:


extension Int: ExampleProtocol {
    var simpleDescription: String {
        return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
}
7.simpleDescription


generics

Swift使用 <> 來聲明泛型函數或泛型類型:


func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] {
    var result = ItemType[]()
    for i in 0..times {
        result += item
    }
    return result
}
repeat("knock", 4)


Swift也支持在 class、enum和結構中使用泛型


enum OptionalValue<T> {
    case None
    case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)



有時需要對泛型做一些需求(requirements),比如需求某個泛型類型實現某個接口或繼承自某個特定類型、兩個泛型類型屬於同一個類型等等,Swift 通過 where 描述這些需求:


func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Bool {
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                return true
            }
        }
    }
    return false
}
anyCommonElements([1, 2, 3], [3])



後記

恭喜你還有耐心看到這一段,繼 wwdc2014 6/2 發佈 swift 至今大約不到兩天
其實我還沒在實際 APP 開發上測試過 object-c 和 swift 兩者性能差異性在哪裡
應該說也來不及測試,發生一事情,mac 已經飛了,也需要存錢買一台
可能要等到很久很久以後才能在來實體測試看看 兩種語言,編寫同一款 app 時候效能差異性在哪裡,可是想必倒時候已經很多公司和網路文章已經出現,應該也輪不到我來說話XDDD  (一笑)

在不到六小時的學習下,Swift 吸收了其它程式語言中的元素,這些元素包括但不限於:

1.協議和擴展源自Objective-C(自家產品隨便用,無所謂)
2.java 的物件導向方式 (拜託 別在 new 了)
3.class和struct的概念和C#極其相似
4.Python風格的宣告語法


未來走向和應用

現有的 iOS 和 OS X 應用開發均使用Objective-C,而 Objective-C 是一門及其繁瑣且學習曲線比較陡的語言
如果 Swift 能夠提供一個同現有 Objective-C 框架的簡易互操作接口,將會有大量的程式開發者轉投 Swift
與此同時,Swift 簡易的語法也會帶來相當數量的其它平台開發者

至於教育,說穿了,從沒期待過學校能交出什笅...台灣這種封閉式教育的空間,除了自身的熱誠外,學校的教育資源只能提供你基礎教育
出了社會職場,一切只能靠你自己,在紡間和網路社群當中,誰能夠一躍而出教導此種語言和廣泛推廣才是上上策,不過大多業界第一線 coding 精神和體力早就被上班壓榨差不多,很少還有多餘時間去教導別人
把學習曲線往下壓,讓更多的人讓更多的人可以更輕易學會寫程式,還是那句老話,出來混的總是要靠自己,只是某某些補習班,別在出來拐騙.....(菸)
Share:

0 意見: