一直以來,我都想好好的研究研究一下這個新語言渤昌。之前雖然用過一段時間侯谁,但一直都覺得不甚了解馆揉。這本書已經(jīng)得到了好久淌喻,期間也斷斷續(xù)續(xù)的讀過镰官,但我的英文水平有限报腔,所以也就是看看示例代碼而已孟岛。這次沸手,又撿起這本書内边。想著可憐巴巴的英文水平曲稼,就想著借這個機(jī)會翻譯翻譯索绪,即便是多數(shù)情況要借助翻譯工具,但接觸的多了贫悄,我的英文水平總該有所改善吧瑞驱。同時又可以細(xì)化自己對這門語言的理解。記得有位大神說過:想讓自己的水平提高窄坦,就試著寫自己的博客吧唤反。
自己最早接觸的語言是C,后來做iOS開發(fā)鸭津,學(xué)習(xí)了OC語言拴袭。對python,js和java有點模糊的認(rèn)知曙博。記得剛接觸OC時拥刻,就無數(shù)次的接觸這樣一個名詞:“面向?qū)ο蟆薄T趯⒔?年的開發(fā)經(jīng)歷中父泳,一直都是使用OC般哼。自從1年前開始接觸swift,發(fā)現(xiàn)這個新語言真真的是好用惠窄。奈何現(xiàn)在公司的項目還沒有考慮使用這門語言蒸眠,所以,自己只能隨便搞搞杆融。最近的工作緊張起來楞卡,希望自己可以堅持翻譯。
Welcome to Swift
About Swift
“Swift is a fantastic way to write software, whether it’s for phones, desktops, servers, or anything else that runs code. It’s a safe, fast, and interactive programming language that combines the best in modern language thinking with wisdom from the wider Apple engineering culture and the diverse contributions from its open-source community. The compiler is optimized for performance and the language is optimized for development, without compromising on either.”
“Swift是編寫軟件的絕佳方式,無論是用于手機(jī)蒋腮,臺式機(jī)淘捡,服務(wù)器還是其他任何運行代碼的軟件。 它是一種安全池摧,快速焦除,交互式的編程語言,它將現(xiàn)代語言思維的最佳結(jié)合與來自更廣泛的Apple工程文化的智慧和來自開源社區(qū)的各種貢獻(xiàn)相結(jié)合作彤。 編譯器針對性能進(jìn)行了優(yōu)化膘魄,語言針對開發(fā)進(jìn)行了優(yōu)化,而且不會影響任何一個竭讳〈雌希”
“Swift is friendly to new programmers. It’s an industrial-quality programming language that’s as expressive and enjoyable as a scripting language. Writing Swift code in a playground lets you experiment with code and see the results immediately, without the overhead of building and running an app.”
“Swift對新程序員友好。 它是一種工業(yè)級編程語言绢慢,與腳本語言一樣富有表現(xiàn)力和樂趣灿渴。 在游樂場中編寫Swift代碼可以讓您試驗代碼并立即查看結(jié)果,而無需構(gòu)建和運行應(yīng)用程序的開銷呐芥。”
“Swift defines away large classes of common programming errors by adopting modern programming patterns:”“Variables are always initialized before use.Array indices are checked for out-of-bounds errors.Integers are checked for overflow.Optionals ensure that nil values are handled explicitly.Memory is managed automatically.Error handling allows controlled recovery from unexpected failures.”
“Swift通過采用現(xiàn)代編程模式來定義大類常見的編程錯誤:”
“變量總是在使用前初始化奋岁。
檢查數(shù)組索引是否存在越界錯誤思瘟。
檢查整數(shù)是否溢出。
Optionals確保明確處理nil值闻伶。
內(nèi)存自動管理滨攻。
錯誤處理允許從意外故障中進(jìn)行受控恢復(fù)±逗玻”
“Swift code is compiled and optimized to get the most out of modern hardware. The syntax and standard library have been designed based on the guiding principle that the obvious way to write your code should also perform the best. Its combination of safety and speed make Swift an excellent choice for everything from “Hello, world!” to an entire operating system.”
“Swift代碼經(jīng)過編譯和優(yōu)化光绕,可以充分利用現(xiàn)代硬件。 語法和標(biāo)準(zhǔn)庫的設(shè)計基于指導(dǎo)原則畜份,即編寫代碼的明顯方法也應(yīng)該表現(xiàn)最佳诞帐。 它的安全性和速度相結(jié)合,使Swift成為從“Hello爆雹,world停蕉!”到整個操作系統(tǒng)的絕佳選擇「铺”
“Swift combines powerful type inference and pattern matching with a modern, lightweight syntax, allowing complex ideas to be expressed in a clear and concise manner. As a result, code is not just easier to write, but easier to read and maintain as well.”
該語言使用強(qiáng)大的類型推斷和現(xiàn)代的模式匹配功能慧起,輕便的語法,“允許以清晰簡潔的方式表達(dá)復(fù)雜的想法”册倒,總而言之蚓挤,代碼不僅簡單易讀,而且容易維護(hù)。
“Swift has been years in the making, and it continues to evolve with new features and capabilities. Our goals for Swift are ambitious. We can’t wait to see what you create with it.”
“Swift多年來一直在不斷發(fā)展灿意,并且隨著新特性和功能的不斷發(fā)展而不斷發(fā)展估灿。 我們對Swift的目標(biāo)雄心勃勃。 我們迫不及待地想看看你用它創(chuàng)造了什么脾歧〖啄螅“
Version Compatibility
“This book describes Swift 4.0, the default version of Swift that’s included in Xcode 9. You can use Xcode 9 to build targets that are written in either Swift 4 or Swift 3.”
“本書描述了Swift 4.0,它是Xcode 9中包含的Swift的默認(rèn)版本鞭执。您可以使用Xcode 9構(gòu)建以Swift 4或Swift 3編寫的目標(biāo)司顿。”
“When you use Xcode 9 to build Swift 3 code, most of the new Swift 4 functionality is available. That said, the following features are available only to Swift 4 code:
Substring operations return an instance of the Substring type, instead of String.
The @objc attribute is implicitly added in fewer places.
Extensions to a type in the same file can access that type’s private members.
“當(dāng)您使用Xcode 9構(gòu)建Swift 3代碼時兄纺,大多數(shù)新的Swift 4功能都可用大溜。 也就是說,以下功能僅適用于Swift 4代碼:
子串操作返回Substring類型的實例估脆,而不是String钦奋。
@objc屬性隱式添加在更少的位置。
對同一文件中的類型的擴(kuò)展可以訪問該類型的私有成員疙赠。
“A target written in Swift 4 can depend on a target that’s written in Swift 3, and vice versa. This means, if you have a large project that’s divided into multiple frameworks, you can migrate your code from Swift 3 to Swift 4 one framework at a time.”
“用Swift 4編寫的目標(biāo)可以依賴于用Swift 3編寫的目標(biāo)付材,反之亦然。 這意味著圃阳,如果您有一個分為多個框架的大型項目厌衔,您可以一次將代碼從Swift 3遷移到Swift 4一個框架『丛溃”
A Swift Tour
“Tradition suggests that the first program in a new language should print the words “Hello, world!” on the screen. In Swift, this can be done in a single line:”
print("Hello, world!")
“If you have written code in C or Objective-C, this syntax looks familiar to you—in Swift, this line of code is a complete program. You don’t need to import a separate library for functionality like input/output or string handling. Code written at global scope is used as the entry point for the program, so you don’t need a main() function. You also don’t need to write semicolons at the end of every statement.”
“如果你用C或Objective-C編寫代碼富寿,這個語法看起來很熟悉 - 在Swift中,這行代碼是一個完整的程序锣夹。 您無需為輸入/輸出或字符串處理等功能導(dǎo)入單獨的庫页徐。 在全局范圍編寫的代碼用作程序的入口點,因此您不需要main()函數(shù)银萍。 你也不需要在每個語句的末尾寫分號变勇。”
“This tour gives you enough information to start writing code in Swift by showing you how to accomplish a variety of programming tasks. Don’t worry if you don’t understand something—everything introduced in this tour is explained in detail in the rest of this book.”
“通過向您展示如何完成各種編程任務(wù)贴唇,本導(dǎo)覽為您提供了足夠的信息來開始在Swift中編寫代碼贰锁。 如果您不理解某些內(nèi)容,請不要擔(dān)心 - 本書其余部分將詳細(xì)介紹本次導(dǎo)覽中介紹的所有內(nèi)容滤蝠⊥阆ǎ”
Simple Values
“Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places.”
“var myVariable = 42
myVariable = 50
let myConstant = 42”
“使用let來創(chuàng)建常量,使用var來創(chuàng)建變量物咳。 在編譯時不需要知道常量的值锣险,但必須為其分配一次值蹄皱。 這意味著您可以使用常量來命名您確定一次但在許多地方使用的值⌒痉簦”
“A constant or variable must have the same type as the value you want to assign to it. However, you don’t always have to write the type explicitly. Providing a value when you create a constant or variable lets the compiler infer its type. In the example above, the compiler infers that myVariable is an integer because its initial value is an integer.”
“常量或變量必須與要分配給它的值具有相同的類型巷折。 但是,您并不總是必須明確地寫入類型崖咨。 在創(chuàng)建常量或變量時提供值可讓編譯器推斷其類型锻拘。 在上面的例子中,編譯器推斷myVariable是一個整數(shù)击蹲,因為它的初始值是一個整數(shù)署拟。”
“If the initial value doesn’t provide enough information (or if there is no initial value), specify the type by writing it after the variable, separated by a colon.”
“如果初始值沒有提供足夠的信息(或者沒有初始值)歌豺,則通過在變量之后寫入來指定類型推穷,用冒號分隔±噙郑”
“l(fā)et implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70”
“Values are never implicitly converted to another type. If you need to convert a value to a different type, explicitly make an instance of the desired type.”
“l(fā)et label = "The width is "
let width = 94
let widthLabel = label + String(width)”
“There’s an even simpler way to include values in strings: Write the value in parentheses, and write a backslash () before the parentheses. For example:”
“l(fā)et apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit.”
“Use three double quotes (""") for strings that take up multiple lines. Indentation at the start of each quoted line is removed, as long as it matches the indentation of the closing quote. For example:”
let quotation = """
Even though there's whitespace to the left,
the actual lines aren't indented.
Except for this line.
Double quotes (") can appear without being escaped.
I still have \(apples + oranges) pieces of fruit.
"""
“Create arrays and dictionaries using brackets ([]), and access their elements by writing the index or key in brackets. A comma is allowed after the last element.”
//arrays
“var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
//dictionaries
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations”
“To create an empty array or dictionary, use the initializer syntax.”
“l(fā)et emptyArray = [String]()
let emptyDictionary = [String: Float]()”
“If type information can be inferred, you can write an empty array as [] and an empty dictionary as [:]—for example, when you set a new value for a variable or pass an argument to a function.”
shoppingList = []
occupations = [:]
“Control Flow
Use if and switch to make conditionals, and use for-in, while, and repeat-while to make loops. Parentheses around the condition or loop variable are optional. Braces around the body are required.”
使用if和switch來制作條件馒铃,并使用for-in,while和repeat-while來制作循環(huán)痕惋。 條件或循環(huán)變量周圍的括號是可選的区宇。 身體周圍的{}是必需的≈荡粒”
“l(fā)et individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore)”
“In an if statement, the conditional must be a Boolean expression—this means that code such as if score { ... } is an error, not an implicit comparison to zero.”
注意:這里與OC中的if的使用是不一樣的议谷。
“You can use if and let together to work with values that might be missing. These values are represented as optionals. An optional value either contains a value or contains nil to indicate that a value is missing. Write a question mark (?) after the type of a value to mark the value as optional.”
“var optionalString: String? = "Hello"
print(optionalString == nil)
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}”
“If the optional value is nil, the conditional is false and the code in braces is skipped. Otherwise, the optional value is unwrapped and assigned to the constant after let, which makes the unwrapped value available inside the block of code.”
“如果可選值為nil,則條件為false述寡,并跳過大括號中的代碼柿隙。 否則叶洞,可選值被解包并在let之后分配給常量鲫凶,這使得在代碼塊內(nèi)可用解包值●帽伲”
“Another way to handle optional values is to provide a default value using the ?? operator. If the optional value is missing, the default value is used instead.”
“處理可選值的另一種方法是使用??提供默認(rèn)值螟炫。 如果缺少可選值,則使用默認(rèn)值艺晴≈缱辏”
“l(fā)et nickName: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickName ?? fullName)”
“Switches support any kind of data and a wide variety of comparison operations—they aren’t limited to integers and tests for equality.”
“Switches支持任何類型的數(shù)據(jù)和各種各樣的比較操作 - 它們不僅限于整數(shù)和相等的數(shù)值》饽”
“l(fā)et vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
}”
講真然评,第一次看到這個的時候,我是無比激動的狈究。
“請注意如何在模式中使用let將模式匹配的值賦給常量碗淌。”
“After executing the code inside the switch case that matched, the program exits from the switch statement. Execution doesn’t continue to the next case, so there is no need to explicitly break out of the switch at the end of each case’s code.”
就是說不用在每個case里面再添加break了。
“You use for-in to iterate over items in a dictionary by providing a pair of names to use for each key-value pair. Dictionaries are an unordered collection, so their keys and values are iterated over in an arbitrary order.”
“通過提供一對用于每個鍵值對的名稱亿眠,您可以使用for-in來迭代字典中的項目碎罚。 字典是一個無序集合,因此它們的鍵和值以任意順序迭代纳像【A遥”
“l(fā)et interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
print(largest)”
“Use while to repeat a block of code until a condition changes. The condition of a loop can be at the end instead, ensuring that the loop is run at least once.”
“var n = 2
while n < 100 {
n *= 2
}
print(n)
var m = 2
repeat {
m *= 2
} while m < 100
print(m)”
“You can keep an index in a loop by using ..< to make a range of indexes.”
“var total = 0
for i in 0..<4 {
total += i
}
print(total)”
“Use ..< to make a range that omits its upper value, and use ... to make a range that includes both values.”
Functions and Closures
“Use func to declare a function. Call a function by following its name with a list of arguments in parentheses. Use -> to separate the parameter names and types from the function’s return type.”
“使用func聲明一個函數(shù)。 通過在括號中使用參數(shù)列表跟隨其名稱來調(diào)用函數(shù)竟趾。 使用 - >將參數(shù)名稱和類型與函數(shù)的返回類型分開憔购。”
“func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")”
“By default, functions use their parameter names as labels for their arguments. Write a custom argument label before the parameter name, or write _ to use no argument label.
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")”
“Use a tuple to make a compound value—for example, to return multiple values from a function. The elements of a tuple can be referred to either by name or by number.”
“func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)”
“Functions can be nested. Nested functions have access to variables that were declared in the outer function. You can use nested functions to organize the code in a function that is long or complex.
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()”
“Functions are a first-class type. This means that a function can return another function as its value.”
“func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)”
是不是各種騷操作滿天飛
“A function can take another function as one of its arguments.
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, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)”
“Functions are actually a special case of closures: blocks of code that can be called later. The code in a closure has access to things like variables and functions that were available in the scope where the closure was created, even if the closure is in a different scope when it is executed—you saw an example of this already with nested functions. You can write a closure without a name by surrounding code with braces ({}). Use in to separate the arguments and return type from the body.”
“函數(shù)實際上是閉包的一種特殊情況:可以在以后調(diào)用的代碼塊潭兽。 閉包中的代碼可以訪問創(chuàng)建閉包的作用域中可用的變量和函數(shù)倦始,即使閉包在執(zhí)行時的不同作用域 - 您已經(jīng)看到了嵌套函數(shù)的示例。 您可以使用大括號({})來編寫沒有名稱的閉包山卦。 用于將參數(shù)和返回類型與正文分開鞋邑。”
“numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})”
“You have several options for writing closures more concisely. When a closure’s type is already known, such as the callback for a delegate, you can omit the type of its parameters, its return type, or both. Single statement closures implicitly return the value of their only statement.
let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)”
“你有幾種選擇來更簡潔地編寫閉包账蓉。 當(dāng)已知閉包的類型(例如委托的回調(diào))時枚碗,可以省略其參數(shù)的類型,返回類型或兩者铸本。 單個語句閉包隱式返回其唯一語句的值肮雨。
“You can refer to parameters by number instead of by name—this approach is especially useful in very short closures. A closure passed as the last argument to a function can appear immediately after the parentheses. When a closure is the only argument to a function, you can omit the parentheses entirely.
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)”
“您可以按編號而不是按名稱來引用參數(shù) - 這種方法在非常短的閉包中特別有用。 作為函數(shù)的最后一個參數(shù)傳遞的閉包可以在括號后面立即出現(xiàn)箱玷。 當(dāng)閉包是函數(shù)的唯一參數(shù)時怨规,可以完全省略括號。
Objects and Classes
“Use class followed by the class’s name to create a class. A property declaration in a class is written the same way as a constant or variable declaration, except that it is in the context of a class. Likewise, method and function declarations are written the same way.”
“class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}”
“使用類后跟類的名稱來創(chuàng)建一個類锡足。 類中的屬性聲明與常量或變量聲明的編寫方式相同波丰,只是它位于類的上下文中。 同樣舶得,方法和函數(shù)聲明也以相同的方式編寫掰烟。”
“Create an instance of a class by putting parentheses after the class name. Use dot syntax to access the properties and methods of the instance.
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()”
“This version of the Shape class is missing something important: an initializer to set up the class when an instance is created. Use init to create one.
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}”
“Notice how self is used to distinguish the name property from the name argument to the initializer. The arguments to the initializer are passed like a function call when you create an instance of the class. Every property needs a value assigned—either in its declaration (as with numberOfSides) or in the initializer (as with name).
Use deinit to create a deinitializer if you need to perform some cleanup before the object is deallocated.
Subclasses include their superclass name after their class name, separated by a colon. There is no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.
【Methods on a subclass that override the superclass’s implementation are marked with override—overriding a method by accident, without override, is detected by the compiler as an error. The compiler also detects methods with override that don’t actually override any method in the superclass.”】
“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()”
“注意self是如何用來區(qū)分name屬性和name參數(shù)到初始化器的沐批。創(chuàng)建類的實例時纫骑,初始化程序的參數(shù)就像函數(shù)調(diào)用一樣傳遞。每個屬性都需要一個賦值 - 在其聲明中(與numberOfSides一樣)或在初始化器中(與name一樣)九孩。
如果需要在取消分配對象之前執(zhí)行一些清理先馆,請使用deinit創(chuàng)建一個deinitializer。
子類在其類名后面包含它們的超類名稱躺彬,用冒號分隔煤墙。類不需要子類化任何標(biāo)準(zhǔn)根類缤底,因此您可以根據(jù)需要包含或省略超類。
【覆蓋超類的實現(xiàn)的子類上的方法標(biāo)記為覆蓋 - 覆蓋方法意外番捂,沒有覆蓋个唧,編譯器將其檢測為錯誤。編譯器還檢測具有覆蓋的方法设预,這些方法實際上不會覆蓋超類中的任何方法徙歼。”】(這句話的理解鳖枕,我水平有限魄梯,借助谷歌也就翻譯成這樣,如果大家能夠很好的理解這段話宾符,還煩請大家給我留言)
“In addition to simple properties that are stored, properties can have a getter and a setter.”
“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 triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)”
“In the setter for perimeter, the new value has the implicit name newValue. You can provide an explicit name in parentheses after set.”
“在set設(shè)置器中酿秸,新值具有隱含名稱newValue。 您可以在設(shè)置后在括號中提供顯式名稱魏烫±彼眨”
“Notice that the initializer for the EquilateralTriangle class has three different steps:
Setting the value of properties that the subclass declares.
Calling the superclass’s initializer.
Changing the value of properties defined by the superclass. Any additional setup work that uses methods, getters, or setters can also be done at this point.”
“If you don’t need to compute the property but still need to provide code that is run before and after setting a new value, use willSet and didSet. The code you provide is run any time the value changes outside of an initializer. For example, the class below ensures that the side length of its triangle is always the same as the side length of its square.
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)”
“如果您不需要計算屬性但仍需要提供在設(shè)置新值之前和之后運行的代碼,請使用willSet和didSet哄褒。 您提供的代碼在值在初始化程序之外更改時運行稀蟋。 例如,下面的類確保其三角形的邊長始終與其正方形的邊長相同呐赡。
“When working with optional values, you can write ? before operations like methods, properties, and subscripting. If the value before the ? is nil, everything after the ? is ignored and the value of the whole expression is nil. Otherwise, the optional value is unwrapped, and everything after the ? acts on the unwrapped value. In both cases, the value of the whole expression is an optional value.
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength”
“使用可選值時退客,在諸如方法,屬性和下標(biāo)之類的操作之前你可以寫链嘀?萌狂。 如果?之前的值是零怀泊,那么茫藏?之后的所有值都被忽略,整個表達(dá)式的值為零包个。 否則刷允,可選值解包冤留,并且后面的一切都是碧囊? 對未包裝的價值采取行動。 在這兩種情況下纤怒,整個表達(dá)式的值都是可選值糯而。
Enumerations and Structures
“Use enum to create an enumeration. Like classes and all other named types, enumerations can have methods associated with them.
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”
“By default, Swift assigns the raw values starting at zero and incrementing by one each time, but you can change this behavior by explicitly specifying values. In the example above, Ace is explicitly given a raw value of 1, and the rest of the raw values are assigned in order. You can also use strings or floating-point numbers as the raw type of an enumeration. Use the rawValue property to access the raw value of an enumeration case.
Use the init?(rawValue:) initializer to make an instance of an enumeration from a raw value. It returns either the enumeration case matching the raw value or nil if there is no matching”
if let convertedRank = Rank(rawValue: 3) {
let threeDescription = convertedRank.simpleDescription()
}”
“The case values of an enumeration are actual values, not just another way of writing their raw values. In fact, in cases where there isn’t a meaningful raw value, you don’t have to provide one.
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()”
不一定設(shè)置原始值
“Notice the two ways that the hearts case of the enumeration is referred to above: When assigning a value to the hearts constant, the enumeration case Suit.hearts is referred to by its full name because the constant doesn’t have an explicit type specified. Inside the switch, the enumeration case is referred to by the abbreviated form .hearts because the value of self is already known to be a suit. You can use the abbreviated form anytime the value’s type is already known.”
“If an enumeration has raw values, those values are determined as part of the declaration, which means every instance of a particular enumeration case always has the same raw value. Another choice for enumeration cases is to have values associated with the case—these values are determined when you make the instance, and they can be different for each instance of an enumeration case. You can think of the associated values as behaving like stored properties of the enumeration case instance. For example, consider the case of requesting the sunrise and sunset times from a server. The server either responds with the requested information, or it responds with a description of what went wrong.
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)")
}”
“如果枚舉具有原始值,則這些值將作為聲明的一部分確定泊窘,這意味著特定枚舉情況的每個實例始終具有相同的原始值熄驼。枚舉情況的另一個選擇是使值與案例相關(guān)聯(lián) - 這些值在您創(chuàng)建實例時確定像寒,并且對于枚舉案例的每個實例它們可以不同。您可以將關(guān)聯(lián)值視為與枚舉案例實例的存儲屬性相似瓜贾。例如诺祸,考慮從服務(wù)器請求日出和日落時間的情況。服務(wù)器響應(yīng)所請求的信息祭芦,或者響應(yīng)錯誤的描述筷笨。
“Notice how the sunrise and sunset times are extracted from the ServerResponse value as part of matching the value against the switch cases.
Use struct to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are 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()”
Protocols and Extensions
“Use protocol to declare a protocol.
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
Classes, enumerations, and structs can all adopt protocols.
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”
“Notice the use of the mutating keyword in the declaration of SimpleStructure to mark a method that modifies the structure. The declaration of SimpleClass doesn’t need any of its methods marked as mutating because methods on a class can always modify the class.
“請注意,在SimpleStructure聲明中使用mutating關(guān)鍵字來標(biāo)記修改結(jié)構(gòu)的方法龟劲。 SimpleClass的聲明不需要任何標(biāo)記為變異的方法胃夏,因為類上的方法總是可以修改類。
Use ext ension to add functionality to an existing type, such as new methods and computed properties. You can use an extension to add protocol conformance to a type that is declared elsewhere, or even to a type that you imported from a library or framework.”
“extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)”
使用擴(kuò)展向現(xiàn)有類型添加功能昌跌,例如新方法和計算屬性仰禀。 您可以使用擴(kuò)展來將協(xié)議一致性添加到在其他地方聲明的類型,甚至是從庫或框架中導(dǎo)入的類型蚕愤〈鸲瘢”
“You can use a protocol name just like any other named type—for example, to create a collection of objects that have different types but that all conform to a single protocol. When you work with values whose type is a protocol type, methods outside the protocol definition are not available.
let protocolVlet protocolValue: ExampleProtocol = a
print(protocolValue.simpleDescription)
// print(protocolValue.anotherProperty)
// Uncomment to see the error
“您可以像使用任何其他命名類型一樣使用協(xié)議名稱 - 例如,創(chuàng)建具有不同類型但都符合單個協(xié)議的對象集合萍诱。 使用類型為協(xié)議類型的值時亥宿,協(xié)議定義之外的方法不可用。
Even though the variable protocolValue has a runtime type of SimpleClass, the compiler treats it as the given type of ExampleProtocol. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.”
即使變量protocolValue具有SimpleClass的運行時類型砂沛,編譯器也會將其視為給定類型的ExampleProtocol烫扼。 這意味著除了協(xié)議一致性之外,您不會意外地訪問該類實現(xiàn)的方法或?qū)傩园帧映企!?/h6>
Error Handling
“You represent errors using any type that adopts the Error protocol.”
“enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}”
“Use throw to throw an error and throws to mark a function that can throw an error. If you throw an error in a function, the function returns immediately and the code that called the function handles the error.”
“func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.noToner
}
return "Job sent"
}”
“There are several ways to handle errors. One way is to use do-catch. Inside the do block, you mark code that can throw an error by writing try in front of it. Inside the catch block, the error is automatically given the name error unless you give it a different name.”
“do {
let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
print(printerResponse)
} catch {
print(error)
}”
“You can provide multiple catch blocks that handle specific errors. You write a pattern after catch just as you do after case in a switch.”
“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)
}”
“Another way to handle errors is to use try? to convert the result to an optional. If the function throws an error, the specific error is discarded and the result is nil. Otherwise, the result is an optional containing the value that the function returned.”
“l(fā)et printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")”
“處理錯誤的另一種方法是使用try? 將結(jié)果轉(zhuǎn)換為可選静浴。 如果函數(shù)拋出錯誤堰氓,則丟棄特定錯誤,結(jié)果為nil苹享。 否則双絮,結(jié)果是一個可選的,包含函數(shù)返回的值得问《谂剩”
“Use defer to write a block of code that is executed after all other code in the function, just before the function returns. The code is executed regardless of whether the function throws an error. You can use defer to write setup and cleanup code next to each other, even though they need to be executed at different times.”
“var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]
func fridgeContains(_ food: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(food)
return result
}
fridgeContains("banana")
print(fridgeIsOpen)”
“使用defer編寫一個代碼塊,該代碼塊在函數(shù)中的所有其他代碼之后執(zhí)行宫纬,就在函數(shù)返回之前焚挠。 無論函數(shù)是否拋出錯誤,都會執(zhí)行代碼漓骚。 你可以使用defer來編寫彼此相鄰的設(shè)置和清理代碼蝌衔,即使它們需要在不同的時間執(zhí)行榛泛。”
Generics
“Write a name inside angle brackets to make a generic function or type.
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)”
“You can make generic forms of functions and methods, as well as classes, enumerations, and structures.
// Reimplement the Swift standard library's optional type
enum OptionalValue<Wrapped> {
case none
case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none
possibleInteger = .some(100)”
“Use where right before the body to specify a list of requirements—for example, to require the type to implement a protocol, to require two types to be the same, or to require a class to have a particular superclass.
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1, 2, 3], [3])”
“Writing <T: Equatable> is the same as writing <T> ... where T: Equatable.”