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