原文:http://blog.xsoin.com/2014/06/swift.html
前言
環境 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,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,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,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,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 精神和體力早就被上班壓榨差不多,很少還有多餘時間去教導別人
把學習曲線往下壓,讓更多的人讓更多的人可以更輕易學會寫程式,還是那句老話,出來混的總是要靠自己,只是某某些補習班,別在出來拐騙.....(菸)