Swift是蘋果于2014年推出的一種新語言。Swfit 將替換 Objective-C,成為 iOS 和 Mac 的推薦開發(fā)語言。在本章中,您將重點學習Swift的基礎知識。 你不會學到所有的知識,但是你會學到足夠的知識來入門。 然后,當您繼續(xù)閱讀本書時,您將在學習 iOS 開發(fā)的過程中學到更多。
Swift 保持 Objective-C 的表現(xiàn)力,同時引入更安全,簡潔和可讀的語法。它強調(diào)類型安全性,并增加了高級功能,如可選項,泛型,復雜結構和枚舉。最重要的是,在開發(fā)人員多年來構建的、經(jīng)過測試的、高級的 iOS 框架中也能使用這些新功能。
如果你在用 Swift 進行iOS開發(fā)的時候感到困難,您可能需要從 Swift Programming:The Big Nerd Ranch Guide
或 Apple 的 Swift教程 開始,您可以在 developer.apple.com/
中找到。 但是,如果你有一些編程經(jīng)驗,并想在工作中運用,你可以在這里開始你的 Swift 學習。
Swfit 的類型
Swift 類型可以分為三個基本組:結構體(structure)
,類(class)
和 枚舉(enumeration)
(圖2.1)。 所有三個可以有:
- 屬性 - 與類型相關聯(lián)的值
- 構造器 - 初始化類型實例的代碼
- 實例方法 - 在該類型的實例上調(diào)用的函數(shù)
- 類或靜態(tài)方法 - 在類型本身上調(diào)用的函數(shù)
圖2.1 Swift 構建塊
Swift 的結構體和枚舉比大多數(shù)語言更加強大。 除了支持屬性,構造器和方法之外,它們還可以符合協(xié)議并可以擴展。
Swift 原始數(shù)據(jù)類型(如數(shù)字和布爾值)的實現(xiàn)可能會讓您感到驚訝:它們都是結構體。 事實上,所有這些 Swift 類型都是結構體:
數(shù)字類型: Int, Float, Double
布爾類型: Bool
文本類型: String, Character
集合類型: Array<Element>, Dictionary<Key:Hashable,Value>,Set<Element:Hashable>
這意味著基礎類型也具有屬性,構造器和自己的方法。 它們也可以符合協(xié)議并擴展。
最后,Swift 的一個關鍵特性是 可選項(optional)
。 可選項允許您存儲特定類型的值或根本沒有值。 您將在本章后面更多地了解可選項及其在 Swift 中的作用。
使用標準類型
在本節(jié)中,您將在 Xcode playground
中嘗試使用標準類型。 playground
可讓您編寫代碼并查看結果,而無需手動運行應用程序和檢查輸出。
在 Xcode
中,選擇 File
→ New
→ Playground...
方便起見,你可以使用此文件的默認名稱。 確保 platform 是 iOS
(圖2.2)。
圖2.2配置playground
單擊 Next
并將其保存在方便的位置。
當文件打開時,請注意,playground 分為兩個部分(圖2.3)。 左側較大的白色區(qū)域是您編寫代碼的編輯器。 右側的灰色列是側邊欄。 playground 在每行后編譯并執(zhí)行您的代碼,并在側邊欄中顯示結果。
圖2.3一個playground
在示例代碼中,var
關鍵字表示一個變量,因此 str 的值可以從其初始值更改。 鍵入以下代碼以更改 str 的值,您將看到結果顯示在右側的邊欄中。
var str = "Hello, playground"
????"Hello, playground"
str = "Hello, Swift"
????????"Hello, Swift"
(請注意,我們會在右邊顯示側邊欄的結果,給那些沒有積極地進行練習的讀者看。)
let
關鍵字表示不能更改的常量值。 在您的 Swift 代碼中,您應該多使用 let,除非您期望該值需要更改。 添加一個常量:
var str = "Hello, playground"
????"Hello, playground"
str = "Hello, Swift"
????????"Hello, Swift"
let constStr = str
?????????"Hello, Swift"
因為constStr是一個常量,所以嘗試改變它的值會導致一個錯誤。
var str = "Hello, playground"
????"Hello, playground"
str = "Hello, Swift"
????????"Hello, Swift"
let constStr = str
?????????"Hello, Swift"
constStr = "Hello, world"
出現(xiàn)錯誤的話,會在錯誤行左側用紅色符號表示。 單擊符號以獲取有關錯誤的更多信息。 在這種情況下,錯誤是
Cannot assign to value: 'constStr' is a 'let' constant.
無法分配給值:'constStr' 是一個 'let' 常量。
playground 代碼中的錯誤將阻止您在側邊欄中看到任何進一步的結果,因此您通常希望立即解決問題。 刪除嘗試更改 constStr 的值的行。
var str = "Hello, playground"
????"Hello, playground"
str = "Hello, Swift"
????????"Hello, Swift"
let constStr = str
?????????"Hello, Swift"
constStr = "Hello, world"
類型推斷
在這一點上,您可能已經(jīng)注意到,constStr 常量和 str 變量都不具有指定的類型。 這并不意味著他們是沒有類型的! 編譯器會從初始值推斷出它們的類型。 這稱為類型推斷。
您可以使用 Xcode 的快速幫助找出推斷的類型。 按住 Alt 在 playground 上單擊 constStr 以查看該常量的快速幫助信息(譯者注:此處虛擬機中按 Alt,Mac 是 Option 鍵 ),如圖2.4所示。
圖2.4 constStr是String類型
Alt-單擊顯示快速幫助將適用于任何對象。
指定類型
如果常數(shù)或變量具有初始值,則可以依賴類型推斷。 如果常數(shù)或變量沒有初始值,或者如果要確保它是某種類型,則可以在聲明中指定類型。
添加指定類型的更多變量:
var str = "Hello, playground"
????"Hello, playground"
str = "Hello, Swift"
????????"Hello, Swift"
let constStr = str
?????????"Hello, Swift"
var nextYear: Int
var bodyTemp: Float
var hasPet: Bool
請注意,邊欄沒有報告任何結果,因為這些變量還沒有值。
我們來看看這些新的類型以及它們的使用方式。
數(shù)字和布爾類型
整數(shù)最常見的類型是 Int。 還有基于數(shù)字長度和符號類型的整數(shù)類型,但是蘋果建議使用 Int,除非你真的有使用別的類型的理由。
對于浮點數(shù),Swift提供了三種不同精度的類型:
Float 為32位,Double 為64位,Float80 為80位。
集合類型
Swift 標準庫提供三個集合:數(shù)組(array),字典(dictionary) 和 集合(set)。
數(shù)組是元素的有序集合。 數(shù)組類型寫為 Array <T>,其中 T 是數(shù)組將包含的元素的類型。 數(shù)組可以包含任何類型的元素:標準類型,結構體或類。
為整數(shù)數(shù)組添加一個變量:
var hasPet: Bool
var arrayOfInts: Array<Int>
數(shù)組是強類型的。 一旦將數(shù)組聲明為包含 Int 的元素,就不能向其添加一個 String。
有一個用于聲明數(shù)組的簡寫語法:您可以簡單地在數(shù)組將包含的類型周圍使用方括號。 更新 arrayOfInts 的聲明以使用簡寫:
var hasPet: Bool
var arrayOfInts: Array<Int>
var arrayOfInts: [Int]
字典是鍵值對的無序集合。 值(value)可以是任何類型,包括結構體和類。 鍵(key)也可以是任何類型,但它們必須是唯一的。 具體來說,key 必須是 可哈希(hastable) 的,這允許字典保證 key 是唯一的,并且更有效地訪問給定 key 的值。 基本的 Swift 類型,如 Int,Float,Character 和 String 都是可哈希的。
像 Swift 數(shù)組一樣,Swift 字典也是強類型的,只能包含聲明類型的 鍵(key) 和 值(value)。 例如,您可能有一個字典,按國家/地區(qū)存儲首都。 這個字典的 鍵(key) 將是國名,值將是城市名稱。 鍵和值都將是字符串,您將無法添加任何其他類型的鍵或值。
為這樣的字典添加一個變量:
var arrayOfInts: [Int]
var dictionaryOfCapitalsByCountry: Dictionary<String,String>
還有一個用于聲明字典的簡寫語法。 更新 dictionaryOfCapitalsByCountry
使用簡寫:
var arrayOfInts: [Int]
var dictionaryOfCapitalsByCountry: Dictionary<String,String>
var dictionaryOfCapitalsByCountry: [String:String]
一個集合類似于一個數(shù)組,因為它包含一些特定類型的元素。 然而,集合是無序的,成員必須是唯一的,并且是 可哈希的(hashable) 。 當您只需要確定某個東西是否是一個集合的成員時,集合的無序性使得它們更快。 為集合添加一個變量:
var winningLotteryNumbers: Set<Int>
與數(shù)組和字典不同,集合沒有縮寫語法。
字面值和下標
可以為標準類型分配字面值。 例如,str 被賦予字符串字面值。 字符串字面值用雙引號形成。 將分配給 str 的字面值與分配給 constStr 的非字面值進行對比:
var str = "Hello, playground"
????"Hello, playground"
str = "Hello, Swift"
????????"Hello, Swift"
let constStr = str
?????????"Hello, Swift"
在 playground 上添加兩個數(shù)字字面值:
let number = 42
????????????42
let fmStation = 91.1
??????????91.1
數(shù)組和字典也可以分配字面值。 創(chuàng)建文字數(shù)組和字典的語法類似于用于指定這些類型的簡寫語法。
let countingUp = ["one", "two"]
????????????????["one", "two"]
let nameByParkingSpace = [13: "Alice", 27: "Bob"]
???????[13: "Alice", 27: "Bob"]
Swift 還提供下標作為訪問數(shù)組的速記。 要檢索數(shù)組中的元素,您可以在數(shù)組名后面的方括號中提供元素的索引。
let countingUp = ["one", "two"]
??????????["one", "two"]
let secondElement = countingUp[1]
?????????"two"
...
請注意, 數(shù)組的下標始終從 0 開始,下標 1 檢索第二個元素。
檢索數(shù)組時,請確保使用有效的下標。 嘗試訪問超出范圍的下標會導致 trap(程序中斷)。 trap 是運行時錯誤,在程序進入未知狀態(tài)之前終止程序。
下標也適用于字典——在本章后面講解。
構造器
到目前為止,您已經(jīng)使用字面值初始化了常量和變量。 在這樣做時,您創(chuàng)建了一個特定類型的實例。 實例(instance) 是類型的特定實例。 從歷史上看,這個術語只用于課堂,但在 Swift 中,它也用于描述結構體和枚舉。 例如,常量 secondElement 包含一個 String 的實例。
創(chuàng)建實例的另一種方法是在類型上使用 構造器(initializer)。 構造器負責準備新類型實例的內(nèi)容。構造器執(zhí)行完成后,該實例已準備就緒。 要使用構造器創(chuàng)建新實例,可以使用類型名稱后跟一對括號,如果需要,則加上參數(shù)。 該類型和參數(shù)的組合對應于特定的構造器。
一些標準類型也具有構造器,當沒有提供參數(shù)時返回空文本。 向 playground 添加一個空字符串,一個空數(shù)組和一個空集。
let emptyString = String()
??????????""
let emptyArrayOfInts = [Int]()
???????? 0 elements
let emptySetOfFloats = Set<Float>()
??????0 elements
其他類型具有默認值:
let defaultNumber = Int()
??????0
let defaultBool = Bool()
??????false
類型可以有多個構造器。 例如,String 具有接受 Int 的構造器,并根據(jù)該值創(chuàng)建一個字符串。
let number = 42
???????????????42
let meaningOfLife = String(number)
??????"42"
要創(chuàng)建一個集合,可以使用接受數(shù)組字面量的 Set 構造器:
let availableRooms = Set([205, 411, 412])
?????{412, 205, 411}
Float 有幾個構造器。 無參數(shù)構造器返回具有默認值的 Float 實例。 還有一個接受浮點數(shù)字的構造器。
let defaultFloat = Float()
???????0.0
let floatFromLiteral = Float(3.14)
??? 3.14
如果對浮點文字使用類型推斷,則類型默認為 Double。 使用浮點文字創(chuàng)建以下常量:
let easyPi = 3.14
?????????3.14
使用接受 Double 的 Float 構造器,從此 Double 創(chuàng)建一個 Float:
let easyPi = 3.14
?????????????3.14
let floatFromDouble = Float(easyPi)
?????3.14
您可以通過在聲明中指定類型來實現(xiàn)相同的結果。
let easyPi = 3.14
??????????3.14
let floatFromDouble = Float(easyPi)
??3.14
let floatingPi: Float = 3.14
?????3.14
屬性
屬性是與類型實例相關聯(lián)的值。 例如,String 具有屬性 isEmpty,它是一個 Bool,它告訴您字符串是否為空。 Array <T> 具有屬性 count,它是數(shù)組中的元素數(shù)量,為 Int。 在 playground 上訪問這些屬性:
let countingUp = ["one", "two"]
????["one", "two"]
let secondElement = countingUp[1]
???"two"
countingUp.count
???????????2
...
let emptyString = String()
emptyString.isEmpty
??????????true
實例方法
實例方法是特定于特定類型的函數(shù),可以被該類型的實例調(diào)用。 從 Array <T> 中嘗試 append(_ :) 實例方法。 您將首先需要將 constantUp 數(shù)組從常量更改為變量。
let countingUp = ["one", "two"]
var countingUp = ["one", "two"]
?????["one", "two"]
let secondElement = countingUp[1]
????"two"
countingUp.count
countingUp.append("three")
???????["one", "two", "three"]
append(_ :)方法接受數(shù)組類型的元素,并將其添加到數(shù)組的末尾。 我們將在第3章討論方法,包括命名。
可選值(Optional)
Swift 類型可以是 可選(optional) 的,這通過附加 ?到一個類型名稱來表示 。
var anOptionalFloat: Float?
var anOptionalArrayOfStrings: [String]?
var anOptionalArrayOfOptionalStrings: [String?]?
可選值(optional) 可以表示變量可能根本不存儲值。 可選的值將是指定類型的實例或 nil。
在這本書中,您將有很多機會使用可選值。 以下是一個讓您熟悉語法的示例,以便您以后可以專注于使用可選值。
想象一下樂器讀數(shù):
var reading1: Float
var reading2: Float
var reading3: Float
有時,儀器可能發(fā)生故障,因而不能返回一個 reading。 您不希望這種故障顯示為 0.0。 你希望它是完全不同的東西,告訴你檢查你的樂器或采取一些其他的行動。
您可以通過將讀數(shù)聲明為可選來執(zhí)行此操作。 將這些聲明添加到您的 playground。
var reading1: Float?
??? nil
var reading2: Float?
????nil
var reading3: Float?
????nil
作為可選的浮點數(shù),每個讀數(shù)可以包含 Float 或 nil。 如果沒有給出初始值,則該值默認為 nil。
您可以像任何其他變量一樣將值分配給可選項。 為 reading 變量 分配浮點數(shù)字:
reading1 = 9.8
????9.8
reading2 = 9.2
????9.2
reading3 = 9.7
????9.7
但是,您不能像非可選浮點數(shù)那樣使用這些可選浮點,即使它們已被賦值為 Float。 在讀取可選變量的值之前,必須解決其值為 nil 的可能性。 這被稱為 解包(unwrap) 可選值。
您將嘗試解開一個可選變量的兩種方式:可選綁定和強制解包。 您將首先嘗試執(zhí)行強制展開。 這不是因為它是更好的選擇——其實這是不太安全的選擇。 但是我們先實施強制解包將讓您看到危險,并了解為什么可選綁定通常更好。
要強行解開一個可選項,你可以附加一個! 到它的后面。 首先,嘗試 avgReading,就像它們是非可選變量一樣:
reading1 = 9.8
????????????????9.8
reading2 = 9.2
????????????????9.2
reading3 = 9.7
????????????????9.7
let avgReading = (reading1 + reading2 + reading3) / 3
這會導致錯誤,因為可選值需要先解開。 因此我們強制解開 reading 以解決錯誤:
let avgReading = (reading1 + reading2 + reading3) / 3
let avgReading = (reading1! + reading2! + reading3!) / 3
????9.566667
一切都看起來不錯,能看到邊欄中的正確平均值。 但危險潛伏在于您的代碼中。 當你強行展開一個可選值,你告訴編譯器你確定這個可選值不會是 nil,因而它可以被看作是一個正常的 Float。 但如果不是浮點數(shù)呢? 試著注釋掉 reading3 的賦值語句,這將返回默認值 nil。
reading1 = 9.8
??????9.8
reading2 = 9.2
??????9.2
reading3 = 9.7
// reading3 = 9.7
現(xiàn)在出現(xiàn)了一個錯誤。 Xcode 可能會在 playground 底部打開其調(diào)試區(qū)域,并提供有關錯誤的信息。 如果沒有,請選擇 View → Debug Area → Show Debug Area。 錯誤如下:
fatal error: unexpectedly found nil while unwrapping an Optional value
致命錯誤:在解開可選值時意外發(fā)現(xiàn)為零
如果你強行展開一個可選值,而且該可選值為 nil,那么會導致出現(xiàn) 中斷(trap) 并終止應用程序。
解開可選值的更安全的方法是 可選綁定(optional binding)。 可選綁定在條件 if-let 語句中工作:將可選項分配給相應非可選類型的臨時常量。 如果您的可選值具有值,則分配有效,然后繼續(xù)使用非可選常量。 如果可選是 nil,那么可以使用 else 子句來處理這種情況。
更改您的代碼以使用 if-let 語句來測試所有三個變量中的有效值。
let avgReading = (reading1! + reading2! + reading3!) / 3
if let r1 = reading1,
??let r2 = reading2,
??let r3 = reading3 {
????let avgReading = (r1 + r2 + r3) / 3
} else {
??let errorString = "Instrument reported a reading that was nil."
}
reading3 目前為 nil,所以其對 r3 的賦值失敗,側欄顯示錯誤字符串。
要查看其他情況下的操作,請將將值分配給 reading3 的語句恢復。 現(xiàn)在所有三個讀數(shù)都有值,所有三個變量都是有效的,邊欄更新顯示三個 reading 變量的平均值。
檢索字典
回想一下,數(shù)組超出它的范圍會導致一個 異常(trap)。 而字典則不一樣,檢索字典的結果是可選的:
let nameByParkingSpace = [13: "Alice", 27: "Bob"]
????[13: "Alice", 27: "Bob"]
let space13Assignee: String? = nameByParkingSpace[13]
??"Alice"
let space42Assignee: String? = nameByParkingSpace[42]
??nil
如果 鍵(key) 不在字典中,結果將為零。 與其他可選值一樣,當檢索字典時,通常使用 if-let:
let space13Assignee: String? = nameByParkingSpace[13]
if let space13Assignee = nameByParkingSpace[13] {
??print("Key 13 is assigned in the dictionary!")
}
循環(huán)和字符串插值
Swift 具有您可能熟悉的其他語言的所有控制流程語句:if-else,while,for,for-in,repeat-while 和 switch。 然而,即使如此,它們與你習慣的有一些區(qū)別。 Swift 和 C語言風格的這些語句之間的關鍵區(qū)別在于,在這些語句表達式上不需要括號,Swift 只要求對子句使用大括號。
此外,if 和 while 類語句的表達式必須為 Bool。
Swift 沒有傳統(tǒng)的 C 風格的循環(huán),你可能習慣了。 相反,您可以使用 Swift 的 Range 類型和 for-in 語句更簡單地完成相同的事情:
let range = 0..<countingUp.count
for i in range {
??let string = countingUp[i]
??// Use 'string'
}
枚舉數(shù)組中的項是最直觀的:
for string in countingUp {
??// Use 'string'
}
如果你想要數(shù)組中的每一項的索引呢? Swift的 enumerated() 函數(shù)從其參數(shù)返回整數(shù)和值的序列:
for (i, string) in countingUp.enumerated() {
??// (0, "one"), (1, "two")
}
你會問那些括號是什么? enumerated() 函數(shù)返回一個 元組(tuple) 序列。 元組是與數(shù)組類似的值的有序分組,但元組的每個成員可能有不同的類型。 在這個例子中,元組是 (Int,String) 類型。 在這本書中我們不會花太多時間在元組上,它們不會在iOS API中使用,因為 Objective-C 不支持它們。 但是,它們可以在您的 Swift 代碼中使用。
元組的另一個應用是枚舉字典的內(nèi)容:
let nameByParkingSpace = [13: "Alice", 27: "Bob"]
for (space, name) in nameByParkingSpace {
??let permit = "Space \(space): \(name)"
}
你注意到字符串中的奇怪的標記嗎? 那就是Swift的 字符串插值(string interpolation)。 ( 和 ) 之間的表達式在運行時被檢測并插入到字符串中。 在本示例中,您用的是局部變量,然而這同樣可以在任何有效的 Swift 表達式,如方法調(diào)用中使用。
要查看循環(huán)每次迭代的 permit 變量的值,首先單擊行 let allow = Space\(space):\(name)
結果側邊欄最右端的循環(huán) Show Result 指示符。 您將看到代碼下的 permit 的當前值。 按住 Control 鍵并點擊結果并選擇* Value History*(圖2.5)。 這可以對觀察循環(huán)代碼中發(fā)生的情況非常有用。
圖2.5使用 Value History 來查看字符串插值的結果
枚舉和Switch語句
枚舉是具有離散值集的類型。 定義一個描述 pie 的枚舉:
enum PieType {
??case apple
??case cherry
??case pecan
}
let favoritePie = PieType.apple
Swift 有一個強大的 switch 語句,除了別的以外,它非常適合使用在枚舉值的匹配:
let name: String
switch favoritePie {
case .apple:
??name = "Apple"
case .cherry:
??name = "Cherry"
case .pecan:
??name = "Pecan"
}
switch 語句的 case 必須是詳盡的:必須明確地或通過 default:case 來考慮 switch 表達式的每個可能的值。 與 C 不同的是,Swift switch case 的情況不會落空——它僅執(zhí)行匹配的情況下的代碼。 (如果您需要C的 fall-through 行為,則可以使用 fallthrough 關鍵字顯式請求它。)(譯:也就是Swift 的 Switch 的 case 語句匹配后只執(zhí)行當前 case 后的語句,不會像 C 一樣沒遇到 break 則繼續(xù)執(zhí)行下去)
Switch語句可以匹配許多類型,甚至范圍:
let macOSVersion: Int = ...
switch macOSVersion {
case 0...8:
??print("A big cat")
case 9:
??print("Mavericks")
case 10:
??print("Yosemite")
case 11:
??print("El Capitan")
case 12:
??print("Sierra")
default:
??print("Greetings, people of the future! What's new in 10.\(macOSVersion)?")
}
有關 switch 語句及其模式匹配功能的更多信息,請參閱 Apple 的 Swift編程語言(Swift Programming Language) 指南中的 控制流程(Control Flow) 部分。 (多看幾遍)
枚舉和原始值
Swift枚舉的原始值可以用 case 關聯(lián):
enum PieType:
Int
{
??case apple =
0
??case cherry
??case pecan
}
使用指定的類型,rawValue 可以是 PieType 的實例 ,然后使用該值初始化枚舉類型。 這會返回一個可選的值,因為原始值可能與枚舉的實際情況不符,因此它是可選綁定的絕佳候選。
let pieRawValue = PieType.pecan.rawValue
?// pieRawValue is an Int with a value of 2
if let pieType = PieType(rawValue: pieRawValue) {
??// Got a valid 'pieType'!
}
枚舉的原始值通常是 Int,但它同樣可以是任何整數(shù)或浮點數(shù)類型以及 String 和 Character 類型。
當原始值為整數(shù)類型時,如果未給出顯式值,則值將自動遞增。 對于 PieType,只有 apple case 被賦予了一個明確的值。 cherry 和 pecan 的值分別自動分配為 1 和 2 的原始值。
還有更多關于枚舉的知識。 枚舉的每個 case 都可以具有相關聯(lián)的值。 您將在第20章中了解有關相關值的更多信息。
探索蘋果的Swift文檔
要了解 Apple 的 Swift 文檔,請從 developer.apple.com/swift 開始。 這里有兩個特殊的資源來尋找。 我們建議將其加入書簽并訪問它們,以便您可以查看特定的概念或深入挖掘。
The Swift Programming Language
本指南介紹了Swift的許多功能。 它從基礎開始,包括示例代碼和大量細節(jié)。 它還包含 Swift 的語言參考和正式語法。
Swift Standard Library Reference
標準庫參考文獻列出了Swift類型,協(xié)議和全局(或免費)功能的細節(jié)。
您的作業(yè)是瀏覽 Swift標準庫參考(Swift Standard Library Reference) 的 類型(Types) 部分 以及 Swift編程語言指南(The Swift Programming Language guide) 中的 基礎知識(The Basics) ,字符串(Strings) 和 字符(Characters) 以及 集合類型( Collection Types)。 鞏固您在本章中學到的知識,并熟悉這些資源提供的信息。 如果您在需要時知道在何處查找細節(jié),那么您將會減少要記住它們的壓力——這讓您可以專注于 iOS 開發(fā)。