import UIKit
/// 0
let http404Error = (404,"Not Found");
let (statusCode,statusMeeeage) = http404Error;
print("Not Found \(statusCode),message\(statusMeeeage)");
let possibleNumber = "123"
let covertedNumber = Int(possibleNumber);
print(covertedNumber ?? 0);//a!=nil?a!:b
let age = 5
assert(age >= 0, "A person's age cannot be less than zero")
print((1,"zerb")<(2,"apple"));
// do {
// try makeAsmadWich();
// eatASandwich();
// } catch Error.OutOfCleanDishes {
// let washDishes();
// } catch Error.MissingIngredients(let ingredients) {
// buyGroceries(ingredients);
// }
///一 基本运算符
// 1
let names = ["jack","jim","william"];
for i in 0..<names.count {
print("names\(i) is called \(names[i])");
}
for name in names[..<2] {
print(" is called \(name)");
}
// 2
let range = ...5
range.contains(7) // false 3
range.contains(4) // true 4
range.contains(-1) // true
///二. 字符串和字符
// 1
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin, 3 please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""
print(quotation);
// for character in quotation {
// print(character)
// }
// 2.
let catCharacters: [Character] = ["C", "a", "t", "!", "?"]
let catString = String(catCharacters)
print(catString)
// 3 .
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2 // welcome now equals "hello there!"
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// 4.
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)" // message is "3 times 2.5 is 7.5"
// 5.任意的uicode 标量,写作 \u{n} 里边的 n 是—个 1-8个与合法uicode 码位相 等的16进制数字
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
let dollarSign = "\u{24}"
let blackHeart = "\u{2665}"
let sparklingHeart = "\u{1F496}"
let eAcute: Character = "\u{E9}"
let combinedEAcute: Character = "\u{65}\u{301}"
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// 6 使用 index(before:) 和 index(after:) 方法来访问给定索引的前后”要访问给定索引,更远的索引S你可u使用 index(_:offsetBy:) 方法而不是多次调用这两]方法
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a
// 使用 indices 属性来访问字符串中每]字符的索引”
for index in greeting.indices {
print("\(greeting[index]) ", terminator: "")
}
// 7 要给字符串的特定索引位置插入字符S使用 insert(_:at:) 方法S另外要冲入另—]字符串的内容到特定的索引S使用 insert(contentsOf:at:) 方法”
var hello = "hello"
hello.insert("!", at: hello.endIndex)
//要r字符串的特定索引位置移除字符S使用 remove(at:) 方法S另外要移除—小段特定范 围的字符串S使用 removeSubrange(_:) 方法
hello.insert(contentsOf: " there", at: hello.index(before: hello.endIndex))
hello.remove(at: hello.index(before: hello.endIndex))
let rangeHello = hello.index(hello.endIndex, offsetBy: -6)..<hello.endIndex
hello.removeSubrange(rangeHello)
//8
let fstring = "Hello, world!"
let vindex = fstring.index(of: ",") ?? fstring.endIndex
let substring = fstring[..<vindex]
let newString = String(substring)// 你需要把子字符串转换为 String 实例
/// 集合类型
// 1.
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
someInts.append(3)
someInts = []
var shoppingList: [String] = ["Eggs", "Milk"]
var shoppingList1 = ["Eggs", "Milk"]
// 可使用加赋值运算符 ( += 来在数组末尾添加一个或者多个同类型元素:
shoppingList.append("Flour")
shoppingList += ["Baking Powder"]
//使用下标脚本语法来改变给定索引中已经存在的值:
shoppingList[0] = "Six eggs";
shoppingList[1...3] = ["Bananas", "Apples"];
shoppingList
//要把元素插入到特定的索引,调用数组的 insert(_:at:) 方法
shoppingList.insert("Maple Syrup", at: 0)
let mapleSyrup = shoppingList.remove(at: 0)
let apples = shoppingList.removeLast()
if shoppingList.isEmpty {
}else{
print("The shopping list is not empty.")
}
for item in shoppingList {
print(item)
}
//如果需要每S元素i及值的整数索引I使用 enumerated() 方法来遍历数组
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
// 2 使用默认值创建数组
var threeDoubles = Array(repeating: 0.0, count: 3)
// 3 通过连接两个数组来创建数组
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
// 4. 创建并初始化空合集
// a.hashValue == b.hashValue
var letters = Set<Character>()
letters.insert("a")
print("letters is of type Set<Character> with \(letters.count) items.")
letters = []
// 使用数组字面量创建合集
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// 由a数组字面量中所有的值都是相同类型的ISCi6A 就可i推断 Set<String> 是 favoriteGenres 变量的正确类型
var favoriteGenres1: Set = ["Rock", "Classical", "Hip hop"];
favoriteGenres.insert("Jazz")
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
}else{
print("I have particular music preferences.")
}
//Set 类型是无序的。要i特定的顺序遍历合集的值I使用 sorted() 方法 把合集的元素v为使用 < 运算符排序了的数组返回
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
// 5.基本合集操作
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7];
// 创建一个包含两S合集所有值的新合集. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
//oddDigits.union(evenDigits).sorted()
// 创建一个只包含两个合集共有值的新合集 .[] 公共部分
oddDigits.intersection(evenDigits).sorted()
//创建一个两个合集当中不包含某个合集值的新合集 .[1, 9] A中不在B中
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// 创建一个只包含两S合集各自有的非共有值的新合集. [1, 2, 9] 两个非相交部分
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// 使用“相等运算符 == 来判断两个合集是否包含有相同的值;
// 使用 isSubset(of:) 方法来确定一个合集的所有值是被某个合集包含;
// 使用 isSuperset(of:) 方法来确定一个合集是否包含某个合集的所有值;
// 使用 isStrictSubset(of:) 或者 isStrictSuperset(of:) 方法来确定是个合集是否为 某一个合集的子集或者超集,但并不相等;
// 使用 isDisjoint(with:) 方法来判断两个合集是否拥有完全不同的值。
let houseAnimals: Set = ["?", "?"]
let farmAnimals: Set = ["?", "?", "?", "?", "?"]
let cityAnimals: Set = ["?", "?"]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
// 6.字典
var namesOfIntegers = [Int: String]()
namesOfIntegers[16] = "sixteen"
// 如果内容已经提供了信息Iw就可i用字典字面量创建空字典了I它写做 [:] (在一对方 括号里写一S冒号)
namesOfIntegers = [:]
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin "]
// 字面量中所有的键都有相同的类型,同时所有的值是相同的类型 可推断 [String: String] 就是 airports 字典的正确类型
var airports1 = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
airports["LHR"] = "London"
airports["LHR"] = "London Heathrow"
if airports.isEmpty {
}else{
print("The airports dictionary is empty.")
}
// updateValue(_:forKey:) 方法返回一S字典值类型的可选项值。比如对储存 String 值 的字典来说方法返回 String? 类型的值或者说“可选的 String,可选项包 含了键的旧值如果更新前存在的话,否则就是nil :
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB"){ print("The old value for DUB was \(oldValue).")
}
airports["APL"] = "Apple International"
airports["APL"] = nil
if let removedValue = airports.removeValue(forKey: "DUB") {
print("The removed airport's name is \(removedValue).")
}else{
print("The airports dictionary does not contain a value for DUB.")
}
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
for airportName in airports.values {
print("Airport name: \(airportName)")
// Airport name: Toronto Pearson
}
let airportCodes = [String](airports.keys)
let airportNames = [String](airports.values)
/// 控制流
//1.
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("Hello, \(animalName) has leg\(legCount)!")
}
// 2.
let minutes = 60
let minuteInterval = 5
// 比如说每 5 分钟一个标记,使用 stride(from:to:by:) 函数来跳过不想要的标记
// 闭区间j同样适用使用 stride(from:through:by:) 即可
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
print(tickMark)
}
// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
// 3.
let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
//swift 的 repeat-while 循环是与其C语言中的 do-while 循环类似的。
// 相比 C 和 0bjective-C 里的 switch 语句来说swift 里的 switch 语句不会默认每个 情况的末尾贯穿到下一个情况里。相反swift整个 switch 语句会在匹配到第一个 switch 情 况执行完毕,后退出不再需要显式的 break 语句。
//guard使用 guard 语句来要求 一个条件必须是真才能执行 guard 后的语句。与 if 语句不同 guard 语句总是有一 个 else 分句—— else 分句里的会在条件不真的时候执行。
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
}
/// 函数
//1.
func greet(person:String) -> String {
let greeting = "hello," + person + "!";
return greeting;
}
print(greet(person: "Anna"))
func greet(person: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return greet(person: person)
} else {
return greet(person: person)
}
}
print(greet(person: "Tim", alreadyGreeted: true))
//2. 无返回值的函数 返回一个特殊的类型 Void 。它其实是一个空的元组,作用相当于没有元素的元组,可以写作 ()
func voidGreet(person: String) {
print("Hello, \(person)!")
}
voidGreet(person: "Dave")
// 3.
func printAndCount(string: String) -> Int {
print(string)
return string.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting(string: "hello, world")
// 4.多返回值的函数
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// 5. 可选元组返回类型
func minMaxs(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let bounds = minMaxs(array: [8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// 6. 函数实际参数标签和形式参数名
func someFunction(firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
someFunction(firstParameterName: 1, secondParameterName: 2)
// 7. 指定实际参数标签
//func someFunction(argumentLabel parameterName: Int) {}
func greetLbl(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greetLbl(person: "Bill", from: "Cupertino"))
// 8.省略实际参数标签,如果对于函数的形式参数不想使用实际参数标签的话,可以利用下划线( _ )来为这个 形式参数代替显式的实际参数标签
func someFunction(_ firstParameterName: Int, secondParameterName: Int){}
someFunction(1, secondParameterName: 2)
// 9.默认形式参数值 你可以通过在形式参数类型后给形式参数赋一个值来给函数的任意形式参数定义一个默认值。如果定义了默认值,你就可以在调用函数时候省略这个形式参数
func someFunctionDefult(parameterWithDefault: Int = 12) {}
someFunctionDefult(parameterWithDefault: 6)
someFunctionDefult()
// 10. 可变形式参数 一个可变形式参数可以接受零或者多个特定类型的值。当调用函数的时候你可以利用可变 形式参数来声明形式参数可以被传入值的数量是可变的。可以通过在形式参数的类型名称 后边插入三个点符号( ... )来书写可变形式参数
// 一个函数最多只能有一个可变形式参数
func arithmeticMean(_ numbers: Double...) -> Double {
var total :Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers
// 11. 输入输出形式参数 inout
//输入输出形式参数不能有默认值,可变形式参数不能标记为 inout,如果你给一个形式参数标记了 inout,那么它们也不能标记 var和 let了
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a=b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// 12. 使用函数类型 你可以像使用 Swift 中的其他类型一样使用函数类型。例如,你可以给一个常量或变量定 义一个函数类型,并且为变量指定一个相应的函数。
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
var mathFunction:(Int, Int) -> Int = addTwoInts
print("Result: \(mathFunction(2, 3))")
// 13. 函数类型作为形式参数类型
//你可以利用使用一个函数的类型例如 (Int, Int) -> Int 作为其他函数的形式参数类型。 这允许你预留函数的部分实现从而让函数的调用者在调用函数的时候提供
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int ){
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// 14 . 函数类型作为返回类型
// 你可以利用函数的类型作为另一个函数的返回类型。写法是在函数的返回箭头( -> )后 立即写一个完整的函数类型
// 这两个函数的类型都是 (Int) -> Int
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
return backwards ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backwards: currentValue > 0)
//上面的栗子显示了使变量趋近于零需要一个整数还是一个负数。 currentValue 有一个 3 的初始值,也就是说 currentValue > 0 返回 true ,导致
//chooseStepFunction(backward:) 返回 stepBackward(_:) 函数。一个返回函数的引用存 储在名为 moveNearerToZero 的常量里。
//现在这个 moveNearerToZero 指向了正确的函数,它可以用来进行到零的计算了:
print("Counting to zero:")
while currentValue != 0 {
print("\(currentValue)")
currentValue = moveNearerToZero(currentValue)
}
print("zero!") // 3 ,2,1,0
// 15 .内嵌函数 在函数的内部定义另外一个函数。内嵌函数在默认情况下在外部是被隐藏起来的,但却仍然可以通过包裹它们的函数来调用它们。包裹的函数也可以返回它内部的一个内嵌函数来在另外的范围里使用。
func chooseStepFunctionBlock(backward: Bool) -> (Int) -> Int {
func forwardf(input: Int) -> Int { return input + 1 }
func backwardf(input: Int) -> Int { return input - 1 }
return backward ? backwardf : forwardf
}
var BlockCurrentValue = -4
let oveNearerToZero = chooseStepFunctionBlock(backward: BlockCurrentValue > 0)
while BlockCurrentValue != 0 {
print("\(BlockCurrentValue) ")
BlockCurrentValue = oveNearerToZero(BlockCurrentValue)
}
print("zero!")
/// 闭包
//闭包能够捕获和存储定义在其上下文中的任何常量和变量的引用,这也就是所谓的闭合并 包裹那些常量和变量,因此被称为“闭包”,Swift 能够为你处理所有关于捕获的内存管 理的操作
//全局函数是一个有名字但不会捕获任何值的闭包;
//内嵌函数是一个有名字且能从其上层函数捕获值的闭包;
//闭包表达式是一个轻量级语法所写的可以捕获其上下文中常量或变量值的没有名字的闭
//包。
//{ (parameters) -> (return type) in
// statements
//}
let names = ["Chris","Alex","Ewa","Barry","Daniella"]
//
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2
})
// 1. 尾随闭包
//如果你需要将一个很长的闭包表达式作为函数最后一个实际参数传递给函数,使用尾随闭
//包将增强函数的可读性。尾随闭包是一个被书写在函数形式参数的括号外面(后面)的闭
//包表达式
func someFunctionThatTakesAClosure(closure:() -> Void){}
// here's how you call this function without using a trailing closure
//someFunctionThatTakesAClosure({
// closure's body goes here
//})
// here's how you call this function with a trailing closure instead
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
//如果闭包表达式被用作函数唯一的实际参数并且你把闭包表达式用作尾随闭包,那么调用这个函数的时候你就不需要.在函数的名字后面写一对圆括号 ( ) 。
// 如果闭包表达式作为函数的唯一实际参数传入,而你又使用了尾随闭包的语法,那你就不需要在函数名后边写圆括号了
var reversedNamesTrailing = names.sorted { $0 > $1 }
// 一闭包表达式一节的字符串排列闭包也可以作为一个尾随闭包被书写在sorted(by:) 方法的括号外面
let reversedNamess = names.sorted() { $0 > $1 }
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16,58,510];
let strings = numbers.map {
(number) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
// 2. 捕获值
//一个闭包能够从上下文捕获已被定义的常量和变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍能够在其函数体内引用和修改这些值
//作为一种优化,如果一个值没有改变或者在闭包的外面,Swift 可能会使用这个值的拷贝而不是捕获。 Swift也处理了变量的内存管理操作,当变量不再需要时会被释放
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
//incrementer() 函数是没有任何形式参数, runningTotal 和 amount 不是来自于函数 体的内部,而是通过捕获主函数的 runningTotal 和 amount 把它们内嵌在自身函数内部 供使用。当调用 makeIncrementer 结束时通过引用捕获来确保不会消失,并确保了在下 次再次调用 incrementer 时, runningTotal 将继续增加
//如果你分配了一个闭包给类实例的属性,并且闭包通过引用该实例或者它的成员来捕获实例,你将在闭包和实例间建立一个强引用环。Swift将使用捕获列表来打破这种强引用环
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
incrementByTen()
incrementByTen()
// 3.闭包是引用类型
//incrementBySeven 和 incrementByTen 是常量,但是这些常量指向的闭 包仍可以增加已捕获的变量 runningTotal 的值。这是因为函数和闭包都是引用类型。 无论你什么时候赋值一个函数或者闭包给常量或者变量,你实际上都是将常量和变量设置 为对函数和闭包的引用。这上面这个例子中,闭包选择 incrementByTen 指向一个常量, 而不是闭包它自身的内容。这也意味着你赋值一个闭包到两个不同的常量或变量中,这两个常量或变量都将指向相同 的闭包:
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// 4.逃逸闭包
//当闭包作为一个实际参数传递给一个函数的时候,我们就说这个闭包逃逸了,因为它可以 在函数返回之后被调用。当你声明一个接受闭包作为形式参数的函数时,你可以在形式参 数前写 @escaping 来明确闭包是允许逃逸的。
//闭包可以逃逸的一种方法是被储存在定义于函数外的变量里。比如说,很多函数接收闭包 实际参数来作为启动异步任务的回调。函数在启动任务后返回,但是闭包要直到任务完成 ——闭包需要逃逸,以便于稍后调用
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
// 让闭包 @escaping 意味着你必须在闭包中显式地引用 self ,比如说,下面的代码中, 传给 someFunctionWithEscapingClosure(_:) 的闭包是一个逃逸闭包,也就是说它需要 显式地引用 self 。相反,传给 someFunctionWithNonescapingClosure(_:) 的闭包是非 逃逸闭包,也就是说它可以隐式地引用 self
func someFunctionWithNonescapingClosure(closure:() -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 }
someFunctionWithNonescapingClosure { x = 200 }
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
completionHandlers.first?()
print(instance.x)
// 5.自动闭包
//自动闭包是一种自动创建的用来把作为实际参数传递给函数的表达式打包的闭包。它不接受任何实际参数,并且当它被调用时,它会返回内部打包的表达式的值。这个语法的好处在于通过写普通表达式代替显式闭包而使你省略包围函数形式参数的括号
//调用一个带有自动闭包的函数是很常见的,但实现这类函数就不那么常见了。比如说, assert(condition:message:file:line:) 函数为它的 condition 和 message 形式参数接收一个自动闭包;它的 condition 形式参数只有在调试构建是才评判,而且 message 形式参数只有在 condition 是 false 时才评判。自动闭包允许你延迟处理,因此闭包内部的代码直到你调用它的时候才会运行。对于有副作用或者占用资源的代码来说很有用,因为它可以允许你控制代码何时才进行求值。下面的代码展示了闭包如何延迟求值。
//注意 customerProvider 的类型不是 String 而是 () -> String ——一个不接受实际 参数并且返回一个字符串的函数。
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
print("Now serving \(customerProvider())!")
print(customersInLine.count)
// 当你传一个闭包作为实际参数到函数的时候,你会得到与延迟处理相同的行为。
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
//上边的函数 serve(customer:) 接收一个明确的返回下一个客户名称的闭包。下边的另一 个版本的 serve(customer:) 执行相同的任务但是不使用明确的闭包而是通过@autoclosure 标志标记它的形式参数使用了自动闭包。现在你可以调用函数就像它接收 了一个 String 实际参数而不是闭包。实际参数自动地转换为闭包,因为customerProvider 形式参数的类型被标记为 @autoclosure 标记。
func serve(customer customerProvider: @autoclosure ()-> String){ print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
//如果你想要自动闭包允许逃逸,就同时使用 @autoclosure 和 @escaping 标志 @escaping 标志在上边的逃逸闭包里有详细的解释。
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))
print("Collected \(customerProviders.count) closures.")
for customerProvider in customerProviders {
print("Now serving \(customerProvider())!")
}
////上边的代码中,不是调用传入后作为 customerProvider 实际参数的闭包, collectCustomerProviders(_:) 函数把闭包追加到了 customerProviders 数组的末尾。数组声明在函数的生效范围之外,也就是说数组里的闭包有可能在函数返回之后执行。结 果, customerProvider 实际参数的值必须能够逃逸出函数的生效范围。
/// 枚举
//Swift的枚举成员在被创建时不会分配一个默认的整数值。在上文的 CompassPoint例子中, north, south, east和 west并不代表 0, 1, 2和 3。而相反,不同的枚举成员在它们自己的权限中都是完全合格的值,并且是一个在 CompassPoint中被显式定义的类型。
//当判断一个枚举成员时, switch 语句应该是全覆盖的。 如果 .west 的 case 被省略了,那么代码将不能编译,因为这时表明它并没有覆盖CompassPoint 的所有成员。要求覆盖所有枚举成员是因为这样可以保证枚举成员不会意 外的被漏掉。如果不能为所有枚举成员都提供一个 case ,那你也可以提供一个 default 情况来包含那 些不能被明确写出的成员
// 1.使用 Switch 语句来匹配枚举值
enum CompassPoint {
case north
case south
case east
case west
}
var directionToHead = CompassPoint.west
directionToHead = .east
directionToHead = .south
switch directionToHead {
case .north:
print("Lots of planets have a north")
case .south:
print("LWatch out for penguins")
case .east:
print("Watch out for penguins")
case .west:
print("Where the sun rises")
}
// 2. 遍历枚举情况(case)
//对于某些枚举来说,如果能有一个集合包含了枚举的所有情况就好了。你可以通过在枚举 名字后面写 : CaseIterable 来允许枚举被遍历。Swift 会暴露一个包含对应枚举类型所 有情况的集合名为 allCases 。
enum Beverage: CaseIterable {
case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) beverages available")
//Beverage.allCases 来访问包含 Beverage 枚举所有情况 的集合。你可以把 allCases 当成和其他任意集合——集合的元素就是枚举类型的实例, 所以在这里就是 Beverage 的值。上面的例子计数了有多少个情况,然后下面的例子使用for 循环来遍历所有情况
for beverage in Beverage.allCases {
print(beverage)
}
/// 下标
//下标脚本允许你通过在实例名后面的方括号内写一个或多个值对该类的实例进行查询。它 的语法类似于实例方法和计算属性。使用关键字 subscript 来定义下标,并且指定一个或多个输入形式参数和返回类型,与实例方法一样。与实例方法不同的是,下标可以是读 写也可以是只读的。这个行为通过与计算属性中相同的 getter 和 setter 传达
// subscript(index: Int) -> Int {get {}set(newValue) {}}
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(row: row, column: column), "Index out of")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of")
grid[(row * columns) + column] = newValue
}
}
}
var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
/// 继承
// 1.
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {}
}
let someVehicle = Vehicle()
print("Vehicle: \(someVehicle.description)")
class Bicycle: Vehicle {
var hasBasket = false
}
let bicycle = Bicycle()
bicycle.hasBasket = true
// 2 .在初始化中分配常量属性
class SurveyQuestion {
let text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// prints "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)"
// 3. 默认初始化器
//类的所有属性都有默认值,又由于它是一个没有父类的基类, ShoppingListItem 类自动地获得了一个默认的初始化器,使用默认值设置了它的所有属
//性然后创建了新的实例。( name 属性是一个可选 String 属性,所以它会自动设置为 nil 默认值,尽管这个值没有写在代码里。)上面的栗子给 ShoppingListItem 类使用默
//认初始化器以及初始化器语法创建新的实例,写作 ShoppingListItem() ,并且给这个新 实例赋了一个名为 item 的变量
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
// 4.结构体类型的成员初始化器
//如果结构体类型中没有定义任何自定义初始化器,它会自动获得一个成员初始化器。不同于默认初始化器,结构体会接收成员初始化器即使它的存储属性没有默认值。
//这个成员初始化器是一个快速初始化新结构体实例成员属性的方式。新实例的属性初始值可以通过名称传递到成员初始化器里。
//下面的栗子定义了一个名为 Size 有两个属性分别是 width 和 height 的结构体,这两个属性通过分配默认值0.0 ,从而被推断为 Double类型。
//Size 结构体自动接收一个 init(width:heght:) 成员初始化器,你可以使用它来初始化 一个新的 Size 实例:
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
print(twoByTwo.height)
// 5. 值类型的初始化器委托
//初始化器可以调用其他初始化器来执行部分实例的初始化。这个过程,就是所谓的初始化器委托,避免了多个初始化器里冗余代码
struct dSize {
var width = 0.0, height = 0.0
}
struct dPoint {
var x = 0.0, y = 0.0
}
// 对于值类型,当你写自己自定义的初始化器时可以使用 self.init 从相同的值类型里引用其他初始化器。你只能从初始化器里调用 self.init 。
// 注意如果你为值类型定义了自定义初始化器,你就不能访问那个类型的默认初始化器(或者 是成员初始化器,如果是结构体的话)。这个限制防止别人意外地使用自动初始化器而把复 杂初始化器里提供的额外必要配置给覆盖掉的情况发生。
//如果你想要你自己的自定义值类型能够使用默认初始化器和成员初始化器初始化,以及你的自定义初始化器来初始化,把你的自定义初始化器写在扩展里而不是作为值类型原始实的一部分
struct Rect {
var origin = dPoint()
var size = dSize()
init() {}// 初始化器:和默认初始化器有一样的功能,就是那个如果Rect 没有自定义初始化器,它将会使用的那个默认初始化器
init(origin: dPoint, size: dSize) {//初始化器: 和成员初始化器功能相同,就是如果 Rect 没有自定义的初始化器,它将使用的那个初始化器
self.origin = origin
self.size = size
}
init(center: dPoint, size: dSize) {//它以计算一个基于 center 和 size 值的原点开始。然后调用(或是委托) init(origin:size:) 初始化器,它在合适的属性里储存了新的原点和大小值
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: dPoint(x: originX, y: originY), size: size)
}
}
let basicRect = Rect()
// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)
let originRect = Rect(origin: dPoint(x: 2.0, y: 2.0),size: dSize(width: 5.0, height: 5.0))
// 6. 类的继承和初始化
//所有类的存储属性——包括从它的父类继承的所有属性——都必须在初始化期间分配初始值
//Swift 为类类型定义了两种初始化器以确保所有的存储属性接收一个初始值。这些就是所 谓的指定初始化器和便捷初始化器
//指定初始化器是类的主要初始化器。指定的初始化器可以初始化所有那个类引用的属性并且调用合适的父类初始化器来继续这个初始化过程给父类链
init(parameters) { statements }
convenience init(parameters) { statements}
//为了简化指定和便捷初始化器之间的调用关系,Swift 在初始化器之间的委托调用有下面 的三个规则:
//规则 1 指定初始化器必须从它的直系父类调用指定初始化器。
//规则 2 便捷初始化器必须从相同的类里调用另一个初始化器。
//规则 3 便捷初始化器最终必须调用一个指定初始化器。
//简单记忆的这些规则的方法如下:
//指定初始化器必须总是向上委托。
//便捷初始化器必须总是横向委托。
// 两段式初始化
//Swift 的类初始化是一个两段式过程。在第一个阶段,每一个存储属性被引入类为分配了一个初始值。一旦每个存储属性的初始状态被确定,第二个阶段就开始了,每个类都有机会在新的实例准备使用之前来定制它的存储属性
// Swift编译器执行四种有效的安全检查来确保两段式初始化过程能够顺利完成:
//安全检查1:指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。
//安全检查2:指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做,指定初始化器赋予的新值将被父类中的初始化器所覆盖。
//安全检查3:便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括同类里定义的属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖
//安全检查4:初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用 self 作为值
// 7.初始化器的继承和重写
//不像在 Objective-C 中的子类,Swift 的子类不会默认继承父类的初始化器。Swift 的这 种机制防止父类的简单初始化器被一个更专用的子类继承并被用来创建一个没有完全或错误初始化的新实例的情况发生
//当你写的子类初始化器匹配父类指定初始化器的时候,你实际上可以重写那个初始化器。 因此,在子类的初始化器定义之前你必须写 override 修饰符。如同默认初始化器所描述的那样,即使是自动提供的默认初始化器你也可以重写。
//作为一个重写的属性,方法或下标脚本, override 修饰符的出现会让 Swift 来检查父类 是否有一个匹配的指定初始化器来重写,并且验证你重写的初始化器已经按照意图指定了形式参数。
//当重写父类指定初始化器时,你必须写 override 修饰符,就算你子类初始化器的实现是一个便捷初始化器。
//相反,如同上边类类型的初始化器委托所描述的规则那样,如果你写了一个匹配父类便捷 初始化器的子类初始化器,父类的便捷初始化器将永远不会通过你的子类直接调用。因 此,你的子类不能(严格来讲)提供父类初始化器的重写。当提供一个匹配的父类便捷初始 化器的实现时,你不用写 override 修饰符
class dVehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
}
let vi = dVehicle();
//子类Bicycle 定义了一个自定义初始化器 init() 。这个指定初始化器和 Bicycle 的父 类的指定初始化器相匹配,所以 Bicycle 中的指定初始化器需要带上 override 修饰 符。
//子类可以在初始化时修改继承的变量属性,但是不能修改继承过来的常量属性。
class dBicycle: dVehicle {
override init() {
super.init()
numberOfWheels = 2
}
}
let b = dBicycle()
print("Bicycle: \(b.description)")
// 8.自动初始化器的继承
//子类默认不会继承父类初始化器。总之,在特定的情况下父类初始化器是可以被自动继承的。实际上,这意味着在许多场景中你不必重写父类初始化器,只要可以安全操作,你就可以毫不费力地继承父类的初始化器
//假设你为你子类引入的任何新的属性都提供了默认值,请遵守以下2个规则:
//规则1:如果你的子类没有定义任何指定初始化器,它会自动继承父类所有的指定初始化器。
//规则2:如果你的子类提供了所有父类指定初始化器的实现——要么是通过规则1继承来的,要么 通过在定义中提供自定义实现的——那么它自动继承所有的父类便捷初始化器。就算你的子类添加了更多的便捷初始化器,这些规则仍然适用。
//
// 子类能够以便捷初始化器的形式实现父类指定初始化器来作为满足规则2的一部分
// 9.指定和便捷初始化器的操作
//Food 类提供了没有实际参数的便捷初始化器 init()
//尽管 RecipeIngredient 提供了 init(name: String) 初始化器作为一个便捷初始化器, 然而 RecipeIngredient 类为所有的父类指定初始化器提供了实现。因此,RecipeIngredient 类也自动继承了父类所有的便捷初始化器。
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
//由于它为自己引入的所有属性提供了一个默认值并且自己没有定义任何初始化器,ShoppingListItem会自动从父类继承所有的指定和便捷初始化器。
class dShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}
var breakfastList = [
dShoppingListItem(),
dShoppingListItem(name: "Bacon"),
dShoppingListItem(name: "Eggs", quantity: 6),]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
print(item.description)
}
// 10.可失败初始化器
let btn :UIButton = UIButton();
btn.frame = CGRect(x: 1, y: 1, width: 23, height: 30);
btn.backgroundColor = UIColor.black;
let r = CGRect(x: 1, y: 1, width: 20, height: 20);
let view :UIView = UIView(frame: r);
view.addSubview(btn);
view.alpha = 1;
var a :Int = 10;
let d = 2
let s = 2.0
let rs = Double(d) + s
var t : Double = 0.5;
var b = 1;
var c = a+b;
网友评论