原文:http://blog.xsoin.com/2014/06/swift.html
前言
環境 xcode 6.0
創建新 new -> workspace -> 選擇 project 存放位置@H_301_15@ Save as name 暫定取名為 learnSwift.xcodespace@H_301_15@ 創建新的 project -> OS X -> Application -> CommandLine Tool@H_301_15@ 此時頁面下方 language 可以看到有四種語言 swift object-c c c++@H_301_15@ 選擇 swift 後,輸入 product name -> helloSwift@H_301_15@ 此時左方已經創建出兩個 folder,在專案名稱的裡面已經會存在一個 main.swift 檔案@H_301_15@ 打開檔案後裡面已經預設一行程式碼@H_301_15@ import Foundation@H_301_15@ @H_301_15@ println("Hello,world")@H_301_15@
按下鍵盤的 command + R 運行,或者左上方的箭頭 run@H_301_15@ @H_301_15@ 此時下方的控制台將會輸出 Hello,world 字串@H_301_15@ @H_301_15@ 以上可以看到他的架構比 C 簡易許多,甚是也有 Python 風格存在@H_301_15@ 吸收了 Objective-C 的優點,且更加強大易用,可以使用現有的Cocoa和Cocoa Touch框架,兼具編譯語言的高性能(Performance)和腳本語言的交互性(Interactive)@H_301_15@ 按照 apple 的風格,Swift用來寫iOS和OS X程序已勢必是未來的趨勢,當然也不會去相容於其他系統@H_301_15@ @H_301_15@ PS 還是乖乖準備要買一台自己 mac....orz (請問可以募款集資購買一台嗎,我不是正妹沒有乳溝可以露,所以沒有辦法表示誠意)@H_301_15@ @H_301_15@ 簡易的 helloWorld 已經示範完畢,接下來了解他的變數和常數怎麼應用@H_301_15@ 其實這裡還看到 js 的影子存在@H_301_15@ @H_301_15@ Swift使用var聲明變量,let聲明常數
@H_301_15@ var myVariable = 42@H_301_15@ myVariable = 50@H_301_15@ let myConstant = 42@H_301_15@
類型推導
@H_301_15@ Swift支持 Type Inference,所以上面的程式碼不需指定類型,如果需要指定類型:@H_301_15@ let explicitDouble : Double = 70@H_301_15@
Swift不支持隱式類型轉換(Implicitly casting),所以下面的程式碼需要顯式類型轉換(Explicitly casting)
@H_301_15@ let label = "The width is "@H_301_15@ let width = 94@H_301_15@ let labelWidth = label + String(width)@H_301_15@
字符串格式化
Swift使用\(item)的形式進行字符串格式化:@H_301_15@ let apples = 3@H_301_15@ let oranges = 5@H_301_15@ let appleSummary = "I have \(apples) apples."@H_301_15@ let fruitSummary = "I have \(apples + oranges) pieces of fruit."@H_301_15@
array 和 dictionary@H_301_15@ @H_301_15@ Swift使用 [] 操作符聲明 array 和 dictionary:
@H_301_15@ var shoppingList = ["catfish","water","tulips","blue paint"]@H_301_15@ shoppingList[1] = "bottle of water"@H_301_15@ @H_301_15@ var occupations = [@H_301_15@ "Malcolm": "Captain",@H_301_15@ "Kaylee": "Mechanic",@H_301_15@ ]@H_301_15@ occupations["Jayne"] = "Public Relations"@H_301_15@
一般使用初始化器(initializer)語法宣告空 array 和 dictionary:
@H_301_15@ let emptyArray = String[]()@H_301_15@ let emptyDictionary = Dictionary<String,Float>()@H_301_15@
如果類型信息已知,則可以使用 [] 宣告空 array,使用 [:] 聲明空 dictionary
迴圈
Swift 的迴圈語法含 if 和switch,其餘迴圈還有包含 for-in、for、while 和 do-while,循環/判斷條件不需要括號,但循環/ body 必需括號:
@H_301_15@ let individualscores = [75,43,103,87,12]@H_301_15@ var teamscore = 0@H_301_15@ for score in individualscores {@H_301_15@ if score > 50 {@H_301_15@ teamscore += 3@H_301_15@ } else {@H_301_15@ teamscore += 1@H_301_15@ }@H_301_15@ }@H_301_15@
空類型
結合 if 和 let,可以方便的處理可空變量(nullable variable)。對於空值,需要在類型聲明後添加?顯式標明該類型可空。@H_301_15@ var optionalString: String? = "Hello"@H_301_15@ optionalString == nil@H_301_15@ @H_301_15@ var optionalName: String? = "John Appleseed"@H_301_15@ var gretting = "Hello!"@H_301_15@ if let name = optionalName {@H_301_15@ gretting = "Hello,\(name)"@H_301_15@ }@H_301_15@
switch
Swift中的switch支持各種各樣的比較操作:@H_301_15@ let vegetable = "red pepper"@H_301_15@ switch vegetable {@H_301_15@ case "celery":@H_301_15@ let vegetableComment = "Add some raisins and make ants on a log."@H_301_15@ case "cucumber","watercress":@H_301_15@ let vegetableComment = "That would make a good tea sandwich."@H_301_15@ case let x where x.hasSuffix("pepper"):@H_301_15@ let vegetableComment = "Is it a spicy \(x)?"@H_301_15@ default:@H_301_15@ let vegetableComment = "Everything tastes good in soup."@H_301_15@ }@H_301_15@
for-in除了滾 array 也可以用來 dictionary:
@H_301_15@ let interestingNumbers = [@H_301_15@ "Prime": [2,3,5,7,11,13],@H_301_15@ "Fibonacci": [1,1,2,8],@H_301_15@ "Square": [1,4,9,16,25],@H_301_15@ ]@H_301_15@ var largest = 0@H_301_15@ for (kind,numbers) in interestingNumbers {@H_301_15@ for number in numbers {@H_301_15@ if number > largest {@H_301_15@ largest = number@H_301_15@ }@H_301_15@ }@H_301_15@ }@H_301_15@ largest@H_301_15@
while 迴圈和 do-while 迴圈:
@H_301_15@ var n = 2@H_301_15@ while n < 100 {@H_301_15@ n = n * 2@H_301_15@ }@H_301_15@ n@H_301_15@ @H_301_15@ var m = 2@H_301_15@ do {@H_301_15@ m = m * 2@H_301_15@ } while m < 100@H_301_15@ m@H_301_15@
Swift支持傳統的 for 迴圈,此外也可以通過結合,生成一個區間和 for-in 實現同樣的邏輯。
@H_301_15@ var firstForLoop = 0@H_301_15@ for i in 0..3 {@H_301_15@ firstForLoop += i@H_301_15@ }@H_301_15@ firstForLoop@H_301_15@ @H_301_15@ var secondForLoop = 0@H_301_15@ for var i = 0; i < 3; ++i {@H_301_15@ secondForLoop += 1@H_301_15@ }@H_301_15@ secondForLoop@H_301_15@
函數
Swift使用func關鍵字聲明函數:
@H_301_15@ func greet(name: String,day: String) -> String {@H_301_15@ return "Hello \(name),today is \(day)."@H_301_15@ }@H_301_15@ greet("Bob","Tuesday")@H_301_15@
通過元組(Tuple)返回多個值:
@H_301_15@ func getGasPrices() -> (Double,Double,Double) {@H_301_15@ return (3.59,3.69,3.79)@H_301_15@ }@H_301_15@ getGasPrices()@H_301_15@
支持帶有變長參數的函數:
@H_301_15@ func sumOf(numbers: Int...) -> Int {@H_301_15@ var sum = 0@H_301_15@ for number in numbers {@H_301_15@ sum += number@H_301_15@ }@H_301_15@ return sum@H_301_15@ }@H_301_15@ sumOf()@H_301_15@ sumOf(42,597,12)@H_301_15@
函數也可以嵌套函數:
@H_301_15@ func returnFifteen() -> Int {@H_301_15@ var y = 10@H_301_15@ func add() {@H_301_15@ y += 5@H_301_15@ }@H_301_15@ add()@H_301_15@ return y@H_301_15@ }@H_301_15@ returnFifteen()@H_301_15@
作為對象,函數既可以作為返回值,也可以作為參數傳遞:
@H_301_15@ func makeIncrementer() -> (Int -> Int) {@H_301_15@ func addOne(number: Int) -> Int {@H_301_15@ return 1 + number@H_301_15@ }@H_301_15@ return addOne@H_301_15@ }@H_301_15@ var increment = makeIncrementer()@H_301_15@ increment(7)@H_301_15@
@H_301_15@ func hasAnyMatches(list: Int[],condition: Int -> Bool) -> Bool {@H_301_15@ for item in list {@H_301_15@ if condition(item) {@H_301_15@ return true@H_301_15@ }@H_301_15@ }@H_301_15@ return false@H_301_15@ }@H_301_15@ func lessThanTen(number: Int) -> Bool {@H_301_15@ return number < 10@H_301_15@ }@H_301_15@ var numbers = [20,19,12]@H_301_15@ hasAnyMatches(numbers,lessThanTen)@H_301_15@
Closure 使用
本質來說,函數是特殊 Closure,Swift 中可以利用 {} 宣告匿名Closure:
@H_301_15@ numbers.map({@H_301_15@ (number: Int) -> Int in@H_301_15@ let result = 3 * number@H_301_15@ return result@H_301_15@ })@H_301_15@
當 Closure 的類型已知時,可以使用下面的簡化寫法:
@H_301_15@ numbers.map({ number in 3 * number })@H_301_15@
此外還可以通過參數的位置來使用參數,當函數最後一個參數是 Closure 時,可以使用下面的語法:
@H_301_15@ sort([1,12,2]) { $0 > $1 }@H_301_15@
class 應用
Swift 創建一個 class 為以下方法:
@H_301_15@ class Shape {@H_301_15@ var numberOfSides = 0@H_301_15@ func simpleDescription() -> String {@H_301_15@ return "A shape with \(numberOfSides) sides."@H_301_15@ }@H_301_15@ }@H_301_15@
宣告 Shape 的方式,並調用其字串和方法。
@H_301_15@ var shape = Shape()@H_301_15@ shape.numberOfSides = 7@H_301_15@ var shapeDescription = shape.simpleDescription()@H_301_15@
通過init 宣告,既可以使用 self 引用成員 name,也可以引用 numberOfSides
@H_301_15@ class NamedShape {@H_301_15@ var numberOfSides: Int = 0@H_301_15@ var name: String@H_301_15@ @H_301_15@ init(name: String) {@H_301_15@ self.name = name@H_301_15@ }@H_301_15@ @H_301_15@ func simpleDescription() -> String {@H_301_15@ return "A shape with \(numberOfSides) sides."@H_301_15@ }@H_301_15@ }@H_301_15@
使用deinit進行清理工作。
繼承和 override父類方法
Swift支持繼承和多態(override父類方法):
@H_301_15@ class Square: NamedShape {@H_301_15@ var sideLength: Double@H_301_15@ @H_301_15@ init(sideLength: Double,name: String) {@H_301_15@ self.sideLength = sideLength@H_301_15@ super.init(name: name)@H_301_15@ numberOfSides = 4@H_301_15@ }@H_301_15@ @H_301_15@ func area() -> Double {@H_301_15@ return sideLength * sideLength@H_301_15@ }@H_301_15@ @H_301_15@ override func simpleDescription() -> String {@H_301_15@ return "A square with sides of length \(sideLength)."@H_301_15@ }@H_301_15@ }@H_301_15@ let test = Square(sideLength: 5.2,name: "my test square")@H_301_15@ test.area()@H_301_15@ test.simpleDescription()@H_301_15@
注意:如果這裡的 simpleDescription 方法沒有被標識為 override,則會 compiler 錯誤
屬性
為了簡化代碼,Swift引入了屬性(property),見下面的perimeter字段:
@H_301_15@ class EquilateralTriangle: NamedShape {@H_301_15@ var sideLength: Double = 0.0@H_301_15@ @H_301_15@ init(sideLength: Double,name: String) {@H_301_15@ self.sideLength = sideLength@H_301_15@ super.init(name: name)@H_301_15@ numberOfSides = 3@H_301_15@ }@H_301_15@ @H_301_15@ var perimeter: Double {@H_301_15@ get {@H_301_15@ return 3.0 * sideLength@H_301_15@ }@H_301_15@ set {@H_301_15@ sideLength = newValue / 3.0@H_301_15@ }@H_301_15@ }@H_301_15@ @H_301_15@ override func simpleDescription() -> String {@H_301_15@ return "An equilateral triagle with sides of length \(sideLength)."@H_301_15@ }@H_301_15@ }@H_301_15@ var triangle = EquilateralTriangle(sideLength: 3.1,name: "a triangle")@H_301_15@ triangle.perimeter@H_301_15@ triangle.perimeter = 9.9@H_301_15@ triangle.sideLength@H_301_15@
注意: setter 中,接收的值被自動命名為newValue
willSet和didSet
EquilateralTriangle 的宣告進行了如下操作:
@H_301_15@ class TriangleAndSquare {@H_301_15@ var triangle: EquilateralTriangle {@H_301_15@ willSet {@H_301_15@ square.sideLength = newValue.sideLength@H_301_15@ }@H_301_15@ }@H_301_15@ var square: Square {@H_301_15@ willSet {@H_301_15@ triangle.sideLength = newValue.sideLength@H_301_15@ }@H_301_15@ }@H_301_15@ init(size: Double,name: String) {@H_301_15@ square = Square(sideLength: size,name: name)@H_301_15@ triangle = EquilateralTriangle(sideLength: size,name: name)@H_301_15@ }@H_301_15@ }@H_301_15@ var triangleAndSquare = TriangleAndSquare(size: 10,name: "another test shape")@H_301_15@ triangleAndSquare.square.sideLength@H_301_15@ triangleAndSquare.square = Square(sideLength: 50,name: "larger square")@H_301_15@ triangleAndSquare.triangle.sideLength@H_301_15@
從而保證 triangle 和 square 擁有相等的 sideLength。
調用方法
Swift 中,函數的參數名稱只能在函數內部使用,但方法的參數名稱除了在內部使用外還可以在外部使用(第一個參數除外),例如:
@H_301_15@ class Counter {@H_301_15@ var count: Int = 0@H_301_15@ func incrementBy(amount: Int,numberOfTimes times: Int) {@H_301_15@ count += amount * times@H_301_15@ }@H_301_15@ }@H_301_15@ var counter = Counter()@H_301_15@ counter.incrementBy(2,numberOfTimes: 7)@H_301_15@
注意 Swift 支持為方法參數取別名:在上面的代碼裡,numberOfTimes 向外部,times 向內部。
? 的另一種用途
使用可空值時,? 可以出現在方法、屬性或下標前面。
如果 ? 前的值為 nil,那麼 ? 後面的表達式會被忽略,而原表達式直接返回 nil,例如:
@H_301_15@ let optionalSquare: Square? = Square(sideLength: 2.5,name: "optional@H_301_15@ square")@H_301_15@ let sideLength = optionalSquare?.sideLength@H_301_15@
當 optionalSquare 為 nil 時,sideLength 屬性調用會被忽略。
enum 應用
使用enum創建枚舉——注意 Swift 的 enum 可以關聯方法:
@H_301_15@ enum Rank: Int {@H_301_15@ case Ace = 1@H_301_15@ case Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten@H_301_15@ case Jack,Queen,King@H_301_15@ func simpleDescription() -> String {@H_301_15@ switch self {@H_301_15@ case .Ace:@H_301_15@ return "ace"@H_301_15@ case .Jack:@H_301_15@ return "jack"@H_301_15@ case .Queen:@H_301_15@ return "queen"@H_301_15@ case .King:@H_301_15@ return "king"@H_301_15@ default:@H_301_15@ return String(self.toRaw())@H_301_15@ }@H_301_15@ }@H_301_15@ }@H_301_15@ let ace = Rank.Ace@H_301_15@ let aceRawValue = ace.toRaw()@H_301_15@
使用 toRaw 和 fromRaw 在原始(raw)數值和 enum 之間進行轉換:
@H_301_15@ if let convertedRank = Rank.fromRaw(3) {@H_301_15@ let threeDescription = convertedRank.simpleDescription()@H_301_15@ }@H_301_15@
注意枚舉中的成員值(member value)是實際的值(actual value),和原始值(raw value)沒有必然關聯。
一些情況下枚舉不存在有意義的原始值,這時可以直接忽略原始值:
@H_301_15@ enum Suit {@H_301_15@ case Spades,Hearts,Diamonds,Clubs@H_301_15@ func simpleDescription() -> String {@H_301_15@ switch self {@H_301_15@ case .Spades:@H_301_15@ return "spades"@H_301_15@ case .Hearts:@H_301_15@ return "hearts"@H_301_15@ case .Diamonds:@H_301_15@ return "diamonds"@H_301_15@ case .Clubs:@H_301_15@ return "clubs"@H_301_15@ }@H_301_15@ }@H_301_15@ }@H_301_15@ let hearts = Suit.Hearts@H_301_15@ let heartsDescription = hearts.simpleDescription()@H_301_15@
除了可以關聯方法,enum 還支持在其成員上關聯值,同一 enum 的不同成員可以有不同的關聯的值:
@H_301_15@ enum ServerResponse {@H_301_15@ case Result(String,String)@H_301_15@ case Error(String)@H_301_15@ }@H_301_15@ @H_301_15@ let success = ServerResponse.Result("6:00 am","8:09 pm")@H_301_15@ let failure = ServerResponse.Error("Out of cheese.")@H_301_15@ @H_301_15@ switch success {@H_301_15@ case let .Result(sunrise,sunset):@H_301_15@ let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."@H_301_15@ case let .Error(error):@H_301_15@ let serverResponse = "Failure... \(error)"@H_301_15@ }@H_301_15@
結構 struct
Swift使用 struct 關鍵字創建結構。結構支持構造器和方法這些類的特性。結構和類的最大區別在於:結構的實例按值傳遞(passed by value),而類的實例按引用傳遞(passed by reference)。
@H_301_15@ struct Card {@H_301_15@ var rank: Rank@H_301_15@ var suit: Suit@H_301_15@ func simpleDescription() -> String {@H_301_15@ return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"@H_301_15@ }@H_301_15@ }@H_301_15@ let threeOfSpades = Card(rank: .Three,suit: .Spades)@H_301_15@ let threeOfSpadesDescription = threeOfSpades.simpleDescription()@H_301_15@
協議(protocol)和擴展(extension)
協議
Swift 使用 protocol 定義協議:
@H_301_15@ protocol ExampleProtocol {@H_301_15@ var simpleDescription: String { get }@H_301_15@ mutating func adjust()@H_301_15@ }@H_301_15@
類型、enum 和結構都可以實現(adopt)協議
@H_301_15@ class SimpleClass: ExampleProtocol {@H_301_15@ var simpleDescription: String = "A very simple class."@H_301_15@ var anotherProperty: Int = 69105@H_301_15@ func adjust() {@H_301_15@ simpleDescription += " Now 100% adjusted."@H_301_15@ }@H_301_15@ }@H_301_15@ var a = SimpleClass()@H_301_15@ a.adjust()@H_301_15@ let aDescription = a.simpleDescription@H_301_15@ @H_301_15@ struct SimpleStructure: ExampleProtocol {@H_301_15@ var simpleDescription: String = "A simple structure"@H_301_15@ mutating func adjust() {@H_301_15@ simpleDescription += " (adjusted)"@H_301_15@ }@H_301_15@ }@H_301_15@ var b = SimpleStructure()@H_301_15@ b.adjust()@H_301_15@ let bDescription = b.simpleDescription@H_301_15@
擴展
擴展用於在已有的類型上增加新的功能(比如新的方法或屬性),Swift 使用 extension 宣告擴展:
@H_301_15@ extension Int: ExampleProtocol {@H_301_15@ var simpleDescription: String {@H_301_15@ return "The number \(self)"@H_301_15@ }@H_301_15@ mutating func adjust() {@H_301_15@ self += 42@H_301_15@ }@H_301_15@ }@H_301_15@ 7.simpleDescription@H_301_15@
generics
Swift使用 <> 來聲明泛型函數或泛型類型:
@H_301_15@ func repeat<ItemType>(item: ItemType,times: Int) -> ItemType[] {@H_301_15@ var result = ItemType[]()@H_301_15@ for i in 0..times {@H_301_15@ result += item@H_301_15@ }@H_301_15@ return result@H_301_15@ }@H_301_15@ repeat("knock",4)@H_301_15@
Swift也支持在 class、enum和結構中使用泛型
@H_301_15@ enum OptionalValue<T> {@H_301_15@ case None@H_301_15@ case Some(T)@H_301_15@ }@H_301_15@ var possibleInteger: OptionalValue<Int> = .None@H_301_15@ possibleInteger = .Some(100)@H_301_15@
有時需要對泛型做一些需求(requirements),比如需求某個泛型類型實現某個接口或繼承自某個特定類型、兩個泛型類型屬於同一個類型等等,Swift 通過 where 描述這些需求:
@H_301_15@ func anyCommonElements <T,U where T: Sequence,U: Sequence,T.GeneratorType.Element: Equatable,T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T,rhs: U) -> Bool {@H_301_15@ for lhsItem in lhs {@H_301_15@ for rhsItem in rhs {@H_301_15@ if lhsItem == rhsItem {@H_301_15@ return true@H_301_15@ }@H_301_15@ }@H_301_15@ }@H_301_15@ return false@H_301_15@ }@H_301_15@ anyCommonElements([1,3],[3])@H_301_15@
後記
恭喜你還有耐心看到這一段,繼 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 精神和體力早就被上班壓榨差不多,很少還有多餘時間去教導別人
把學習曲線往下壓,讓更多的人讓更多的人可以更輕易學會寫程式,還是那句老話,出來混的總是要靠自己,只是某某些補習班,別在出來拐騙.....(菸)