Welcome to Swift

Version Compatibility

當使用Swift 4 的編譯器來編譯Swift 3 的代碼時候,編譯器會把它標記為3.2铸敏。所以杆融,可以使用條件編譯block畅涂,例如 if swift(>=3.2) 來編寫代碼,以達到對多個版本的兼容勾邦。

A Swift Tour

swift語句是不需要使用分號結束的蚣录。

Simple Values

使用 let 聲明常量,var 聲明變量眷篇。

let explicitDouble: Double = 70
let implicitInteger = 70

swift 可以根據(jù)我們給變量賦的初值來判斷變量的類型包归,轉換變量類型必須顯示轉換。
使用""" """聲明多行string铅歼。使用[]聲明數(shù)組和字典公壤,使用index 或 key 訪問數(shù)組和字典內(nèi)的元素。

Control Flow

if 和 switch 做條件判斷椎椰,for-in, while, repeat-while做循環(huán)厦幅。條件可以不使用()包裹,執(zhí)行體必須使用{}包裹慨飘。

var optionalString: String? = "Hello"

optionalString 是一個optional變量确憨,表示它可能包含一個值,可能是nil瓤的。
關于optional變量休弃,有幾種特殊用法。

if let name = optionalString {
print(name)
}

let info = "Hi \(nickName ?? "zhangsan")"

switch 支持各種類型數(shù)據(jù)圈膏,而不只是integer塔猾。當滿足某種case,執(zhí)行完畢改case的代碼塊稽坤,會立即退出丈甸,所以不需要在每個case代碼塊后寫break糯俗。

0 ..< 4 => [0, 1, 2, 3]
0 ... 4 => [0, 1, 2, 3, 4]

Functions and Closures

使用 func 聲明函數(shù),使用 -> 分離函數(shù)列表和函數(shù)返回值睦擂。

func greet(person: String, day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")
func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")

函數(shù)的返回值和參數(shù)都可以是一個函數(shù)得湘。

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

函數(shù)是一種特殊的閉包,閉包使用{}包裹代碼塊顿仇,使用 in 分割參數(shù)淘正、返回值 和 代碼體。

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

Objects and Classes

使用class聲明函數(shù)臼闻,函數(shù)內(nèi)屬性和方法的聲明跟變量和方法聲明相同鸿吆。

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

使用類名后跟括號獲得類的實例,使用點語法獲得類中的屬性和方法些阅。

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

關于繼承伞剑,如果某個類的父類是根類,沒有必要顯示的寫上繼承于根類市埋。如果要繼承的話黎泣,需要在類名后面寫上父類,使用:分割缤谎。
如果對象dealloc的時候要做一些清楚操作抒倚,可以做deinit方法。

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()

上述類的init方法坷澡,有三步:
1.給子類種的屬性賦值
2.調(diào)用父類的init方法
3.改變父類定義的屬性的值托呕。其他的使用setter等方法的配置工作也可以在這里完成。

如果要重寫父類中的方法频敛,必須標上override项郊;如果某個方法不是重寫父類的方法,不要標記override斟赚。編譯器會檢查上述兩種情況着降。

也可以給屬性設置setter和getter方法:

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

setter的參數(shù),默認使用newValue拗军。

如果不想計算屬性任洞,但是想在設置改屬性值之前或之后運行某段代碼,可以使用willSet和didSet发侵。在initializer之外改改變屬性的值交掏,會調(diào)用你提供的那段代碼。

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")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)

當操作optional 變量的時候刃鳄,可以在操作后面加盅弛?,包括獲取屬性值、調(diào)用方法等熊尉。如果罐柳?前的值是nil掌腰,那么狰住?后的內(nèi)容會被忽略,整個內(nèi)容也是nil齿梁。否則催植,?之后的內(nèi)容都會被運行勺择。這兩種情況下创南,整個表達式的值也是一個可選值。

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

Enumerations and Structures

使用enum創(chuàng)建枚舉省核,枚舉內(nèi)可以有自己的函數(shù)稿辙。
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.rawValue)
        }
    }
}
let ace = Rank.ace
let aceRawValue = ace.rawValue

swift默認從0開始賦值,我們可以明確給定一個值改變這種行為气忠。
使用rawValue屬性取得枚舉的原始值邻储。
給常量ace賦值,使用的是Rank.ace旧噪,因為ace的類型未知吨娜;在枚舉內(nèi)部使用的是簡略語法.ace,因為這個時候是知道類型的淘钟。 我們可以在任何已知枚舉類型的地方使用簡略語法宦赠。
使用 init?(rawValue:) 初始化一個枚舉,它可能會返回一個與rawValue匹配的枚舉米母,或者nil勾扭。

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

枚舉的枚舉值的rawValue是聲明的時候就確定的,所以枚舉的相同枚舉case在任何時候都是相同的铁瞒;但是枚舉的不同實例的相同case可能不同妙色。??:

enum ServerResponse {
    case result(String, String)
    case failure(String)
}
 
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")

switch success {
case let .result(sunrise, sunset):
    print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
    print("Failure...  \(message)")
}

ServerResponse.result.rawValue = 0。 但是精拟,上述的result的值為 上午六點和下午八點燎斩。可能有一個實例的result值是不同的時間點蜂绎。

上述代碼塊解析:
1.success 和 failure 都是ServerResponse類型栅表。
2.常量success的值是reslut(rawValue = 0)。
3.switch success 师枣,應該這樣說:switch ServerResponse類型的一個常量怪瓶,它的結果有兩種.result 和 .failure

使用struct創(chuàng)建結構體。

結構體支持類的許多行為践美,比如methods 和 initializers洗贰。它們最大的不同是:結構題的傳遞是copy的找岖,而類是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()

Protocols and Extensions

使用protocal聲明協(xié)議敛滋,類许布、枚舉、結構體都可以實現(xiàn)協(xié)議绎晃。
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

在SimpleStructure結構體中蜜唾,有個方法被mutating關鍵字修飾了,表明這個方法會改變結構體庶艾。SimpleClass類中的方法不需要標記mutating袁余,因為類中的方法總是要改變類的。

可以使用 extension為現(xiàn)有類型增加功能咱揍,例如增加方法和計算屬性颖榜。

你可以使用extension讓一個在其他地方定義的類型、甚至是你從一個框架和庫導入的類型來遵循某個協(xié)議煤裙,來改變它的定義掩完。

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

你可以使用協(xié)議名,就像使用其他命名類型一樣來創(chuàng)建一個包含各種不同類型但都遵守一個協(xié)議的集合對象积暖。當你使用這些類型是協(xié)議類型的變量時藤为,只能調(diào)用該協(xié)議里的方法。

Error Handing

使用遵循了Error協(xié)議的類型來表示錯誤夺刑。

enum PrinterError: Error {
    case outOfPaper
    case noToner
    case onFire
}

使用throw拋出錯誤缅疟,使用throws關鍵字表示方法可以拋出錯誤。如果在方法里拋出錯誤遍愿,方法會立即返回存淫,并切調(diào)用方法的代碼處理錯誤。

func send(job: Int, toPrinter printerName: String) throws -> String {
    if printerName == "Never Has Toner" {
        throw PrinterError.noToner
    }
    return "Job sent"
}

這有幾種處理錯誤的方式沼填。一種是使用do-catch桅咆。在do block中,在方法前面使用try標記坞笙,表明它可能會拋出錯誤岩饼。在catch block內(nèi),錯誤被自動命名為error薛夜,除非你明確給出其他名字籍茧。

do {
    let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
    print(printerResponse)
} catch {
    print(error)
}

可以使用多個catch block 來處理特定的錯誤。就像在switch中那樣寫case梯澜。

do {
    let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
    print(printerResponse)
} catch PrinterError.onFire {
    print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {
    print("Printer error: \(printerError).")
} catch {
    print(error)
}

另一種處理錯誤的方式是使用 try? 把函數(shù)返回轉成optional類型寞冯。如果函數(shù)拋出了錯誤,那么錯誤會被拋棄,結果會是nil吮龄。否則結果會是一個返回值類型的optional變量俭茧。

let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")

在函數(shù)中使用defer標記的代碼塊將會被最后執(zhí)行(return 之前)。不管函數(shù)是否拋出錯誤漓帚,這塊代碼都會被執(zhí)行母债。

func fridgeContains(_ food: String) -> Bool {
    fridgeIsOpen = true
    defer {
        fridgeIsOpen = false
    }
    
    let result = fridgeContent.contains(food)
    return result
}

Generics

在<>內(nèi)寫一個名字來創(chuàng)建范型函數(shù)或范型類型。

func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
    var result = [Item]()
    for _ in 0..<numberOfTimes {
        result.append(item)
    }
    return result
}
makeArray(repeating: "knock", numberOfTimes: 4)

不僅可以創(chuàng)建范型函數(shù)胰默、方法场斑,還可以創(chuàng)建范型類漓踢、枚舉牵署、結構體。

enum OptionalValue<Wrapped> {
    case none
    case some(Wrapped)
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喧半,一起剝皮案震驚了整個濱河市奴迅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挺据,老刑警劉巖取具,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異扁耐,居然都是意外死亡暇检,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門婉称,熙熙樓的掌柜王于貴愁眉苦臉地迎上來块仆,“玉大人,你說我怎么就攤上這事王暗』诰荩” “怎么了?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵俗壹,是天一觀的道長科汗。 經(jīng)常有香客問我,道長绷雏,這世上最難降的妖魔是什么头滔? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮涎显,結果婚禮上坤检,老公的妹妹穿的比我還像新娘。我一直安慰自己棺禾,他們只是感情好缀蹄,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般缺前。 火紅的嫁衣襯著肌膚如雪蛀醉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天衅码,我揣著相機與錄音拯刁,去河邊找鬼。 笑死逝段,一個胖子當著我的面吹牛垛玻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奶躯,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼帚桩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嘹黔?” 一聲冷哼從身側響起账嚎,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎儡蔓,沒想到半個月后郭蕉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡喂江,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年召锈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片获询。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡涨岁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出筐付,到底是詐尸還是另有隱情卵惦,我是刑警寧澤,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布瓦戚,位于F島的核電站沮尿,受9級特大地震影響,放射性物質發(fā)生泄漏较解。R本人自食惡果不足惜畜疾,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望印衔。 院中可真熱鬧啡捶,春花似錦、人聲如沸奸焙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至了赌,卻和暖如春墨榄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背勿她。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工袄秩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逢并。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓之剧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親砍聊。 傳聞我的和親對象是個殘疾皇子背稼,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容