Welcome to Swift

Version Compatibility

當(dāng)使用Swift 4 的編譯器來編譯Swift 3 的代碼時候,編譯器會把它標(biāo)記為3.2。所以,可以使用條件編譯block,例如 if swift(>=3.2) 來編寫代碼,以達(dá)到對多個版本的兼容。

A Swift Tour

swift語句是不需要使用分號結(jié)束的。

Simple Values

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

let explicitDouble: Double = 70
let implicitInteger = 70

swift 可以根據(jù)我們給變量賦的初值來判斷變量的類型,轉(zhuǎn)換變量類型必須顯示轉(zhuǎn)換。
使用""" """聲明多行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。
關(guān)于optional變量,有幾種特殊用法。

if let name = optionalString {
print(name)
}

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

switch 支持各種類型數(shù)據(jù),而不只是integer。當(dāng)滿足某種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()

關(guān)于繼承,如果某個類的父類是根類,沒有必要顯示的寫上繼承于根類。如果要繼承的話,需要在類名后面寫上父類,使用:分割。
如果對象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等方法的配置工作也可以在這里完成。

如果要重寫父類中的方法,必須標(biāo)上override;如果某個方法不是重寫父類的方法,不要標(biāo)記override。編譯器會檢查上述兩種情況。

也可以給屬性設(shè)置setter和getter方法:

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

setter的參數(shù),默認(rèn)使用newValue。

如果不想計算屬性,但是想在設(shè)置改屬性值之前或之后運行某段代碼,可以使用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)

當(dāng)操作optional 變量的時候,可以在操作后面加?,包括獲取屬性值、調(diào)用方法等。如果?前的值是nil,那么?后的內(nèi)容會被忽略,整個內(nèi)容也是nil。否則,?之后的內(nèi)容都會被運行。這兩種情況下,整個表達(dá)式的值也是一個可選值。

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默認(rèn)從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 ,應(yīng)該這樣說:switch ServerResponse類型的一個常量,它的結(jié)果有兩種.result 和 .failure

使用struct創(chuàng)建結(jié)構(gòu)體。

結(jié)構(gòu)體支持類的許多行為,比如methods 和 initializers。它們最大的不同是:結(jié)構(gòu)題的傳遞是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é)議,類、枚舉、結(jié)構(gòu)體都可以實現(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結(jié)構(gòu)體中,有個方法被mutating關(guān)鍵字修飾了,表明這個方法會改變結(jié)構(gòu)體。SimpleClass類中的方法不需要標(biāo)記mutating,因為類中的方法總是要改變類的。

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

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

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

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

Error Handing

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

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

使用throw拋出錯誤,使用throws關(guān)鍵字表示方法可以拋出錯誤。如果在方法里拋出錯誤,方法會立即返回,并切調(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標(biāo)記,表明它可能會拋出錯誤。在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ù)返回轉(zhuǎn)成optional類型。如果函數(shù)拋出了錯誤,那么錯誤會被拋棄,結(jié)果會是nil。否則結(jié)果會是一個返回值類型的optional變量。

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

在函數(shù)中使用defer標(biāo)記的代碼塊將會被最后執(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)建范型類、枚舉、結(jié)構(gòu)體。

enum OptionalValue<Wrapped> {
    case none
    case some(Wrapped)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,914評論 2 372

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