共计 24941 个字符,预计需要花费 63 分钟才能阅读完成。
Swift 介绍
Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 利用的新语言。
Swift 是一种平安,疾速和互动的编程语言。
Swift 反对代码预览(playgrounds),这个个性能够容许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看后果。
Swift 通过采纳古代编程模式来防止大量常见编程谬误:
- 变量始终在应用前初始化。
- 查看数组索引超出范围的谬误。
- 查看整数是否溢出。
- 可选值确保明确解决 nil 值。
- 内存被主动治理。
- 错误处理容许从意外故障管制复原。
根底局部
常量和变量
申明常量和变量,常量和变量必须在应用前申明,应用 let 来申明常量,应用 var 来申明变量。
示例:
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
// 类型注解
var welcomeMessage: String
正文
单行正文双正斜杠(//),多行正文(/ 多行的 /)。Swift 的多行正文能够嵌套在其它的多行正文之中。
示例:
// 这是一个正文
/* 这也是一个正文,然而是多行的 */
/* 这是第一个多行正文的结尾 /* 这是第二个被嵌套的多行正文 */ 这是第一个多行正文的结尾 */
分号
Swift 并不强制要求你在每条语句的结尾处应用分号(;)。
同一行内写多条独立的语句必须用分号分隔。
let cat = " "; print(cat) // 输入“”
整数、浮点数
对立应用 Int 能够进步代码的可复用性,防止不同类型数字之间的转换,并且匹配数字的类型推断。
示例:
let minValue = UInt8.min // minValue 为 0,是 UInt8 类型
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型
类型平安和类型推断
Swift 是一门类型平安的语言,这意味着 Swift 能够让你分明地晓得值的类型。
如果你没有显式指定类型,Swift 会应用类型推断来抉择适合的类型。(int、double)。
示例:
let meaningOfLife = 42 // meaningOfLife 会被揣测为 Int 类型
let pi = 3.14159 // pi 会被揣测为 Double 类型
数值型字面量、数值型类型转换
示例:
let decimalInteger = 17
let binaryInteger = 0b10001 // 二进制的 17
let octalInteger = 0o21 // 八进制的 17
let hexadecimalInteger = 0x11 // 十六进制的 17
类型别名
类型别名(type aliases)就是给现有类型定义另一个名字。你能够应用 typealias 关键字来定义类型别名。
示例:
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound 当初是 0
布尔值
示例:
let orangesAreOrange = true
let turnipsAreDelicious = false
元组
元组(tuples)把多个值组合成一个复合值。元组内的值能够是任意类型,并不要求是雷同类型。
示例:
let http404Error = (404, "Not Found") // http404Error 的类型是 (Int, String),值是 (404, "Not Found")
可选类型
应用可选类型(optionals)来解决值可能缺失的状况。可选类型示意两种可能:或者有值,你能够解析可选类型拜访这个值,或者基本没有值。
示例:
var serverResponseCode: Int? = 404 // serverResponseCode 蕴含一个可选的 Int 值 404
serverResponseCode = nil // serverResponseCode 当初不蕴含值
错误处理
错误处理,应答程序执行中可能会遇到的谬误条件。
示例:
func makeASandwich() throws {// ...}
do {try makeASandwich()
eatASandwich()} catch SandwichError.outOfCleanDishes {washDishes()
} catch SandwichError.missingIngredients(let ingredients) {buyGroceries(ingredients)
}
断言和先决条件
断言和先决条件,是在运行时所做的查看。
let age = -3
assert(age >= 0, "A person's age cannot be less than zero") // 因为 age < 0,所以断言会触发
根本运算符
Swift 反对大部分规范 C 语言的运算符,还提供了 C 语言没有的区间运算符,例如 a..<b 或 a…b。
作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这是一个我的 iOS 交换群:642363427 不论你是小白还是大牛欢送入驻,分享 BAT, 阿里面试题、面试教训,探讨技术,大家一起交流学习成长!
赋值运算符,算术运算符,组合赋值运算符,比拟运算符,三元运算符,空合运算符,区间运算符,逻辑运算符
运算符分为一元、二元和三元运算符。
闭区间运算符(a…b)定义一个蕴含从 a 到 b(包含 a 和 b)的所有值的区间。
半开区间运算符(a..<b)定义一个从 a 到 b 但不包含 b 的区间。
闭区间操作符有另一个表达形式,能够表白往一侧有限延长的区间,(a…,…b)。
示例:
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {print("第 \(i + 1) 集体叫 \(names[i])")
}
// 第 1 集体叫 Anna
// 第 2 集体叫 Alex
// 第 3 集体叫 Brian
// 第 4 集体叫 Jack
字符串和字符
字符串字面量,字符串插值,计算字符数量,拜访和批改字符串,子字符串,比拟字符串
初始化空字符串,字符串可变性,字符串是值类型,连贯字符串和字符 (+,+=)。
应用字符,可通过 for-in 循环来遍历字符串,获取字符串中每一个字符的值。
字符串插值是一种构建新字符串的形式,能够在其中蕴含常量、变量、字面量和表达式。能够在已有字符串中插入常量、变量、字面量和表达式从而造成更长的字符串。
Swift 提供了三种形式来比拟文本值:字符串字符相等、前缀相等和后缀相等。
示例:
// 多行字符串字面量
let quotation = """The White Rabbit put on his spectacles."Where shall I begin,
please your Majesty?"he asked."Begin at the beginning,"the King said gravely,"and go on
till you come to the end; then stop.""""
// 上面两个字符串其实是一样的
let singleLineString = "These are the same."
let multilineString = """These are the same."""
// 字符串插值
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message 是 "3 times 2.5 is 7.5"
// 计算字符数量
var word = "cafe"
print("the number of characters in \(word) is \(word.count)")
// 打印输出“the number of characters in cafe is 4”var emptyString = "" // 空字符串字面量
var anotherEmptyString = String() // 初始化办法
// 两个字符串均为空并等价。let catCharacters: [Character] = ["C", "a", "t", "!"]
let catString = String(catCharacters)
print(catString)
// 打印输出:“Cat!”
汇合类型
Swift 语言提供数组(Array)、汇合(Set)和字典(Dictionary)三种根本的汇合类型用来存储汇合数据。数组是有序数据的集。汇合是无序无反复数据的集。字典是无序的键值对的集。
汇合的可变性,数组(Arrays),汇合(Sets),汇合操作,字典
数组应用有序列表存储同一类型的多个值。雷同的值能够屡次呈现在一个数组的不同地位中。
汇合用来存储雷同类型并且没有确定程序的值。当汇合元素程序不重要时或者心愿确保每个元素只呈现一次时能够应用汇合而不是数组。
汇合操作,能够高效地实现汇合的一些基本操作,比方把两个汇合组合到一起,判断两个汇合共有元素,或者判断两个汇合是否全蕴含,局部蕴含或者不相交。
字典是一种无序的汇合,它存储的是键值对之间的关系,其所有键的值须要是雷同的类型,所有值的类型也须要雷同。每个值(value)都关联惟一的键(key),键作为字典中这个值数据的标识符。
示例:
// 汇合
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// 打印“someInts is of type [Int] with 0 items.”var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles 是一种 [Double] 数组,等价于 [0.0, 0.0, 0.0]
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles 被推断为 [Double],等价于 [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 被推断为 [Double],等价于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
// enumerated() 办法遍历数组
var shoppingList: [String] = ["Eggs", "Milk"]
for (index, value) in shoppingList.enumerated() {print("Item \(String(index + 1)): \(value)")
}
控制流
For-In 循环,While 循环(Repeat-While),条件语句,管制转移语句,提前退出(guard),检测 API 可用性
像 if 语句一样,guard 的执行取决于一个表达式的布尔值。咱们能够应用 guard 语句来要求条件必须为真时,以执行 guard 语句后的代码。不同于 if 语句,一个 guard 语句总是有一个 else 从句,如果条件不为真则执行 else 从句中的代码。
Swift 内置反对查看 API 可用性,编译器应用 SDK 中的可用信息来验证咱们的代码中应用的所有 API 在我的项目指定的部署指标上是否可用。如果咱们尝试应用一个不可用的 API,Swift 会在编译时报错。
示例:
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {print("Hello, \(name)!")
}
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {print("\(animalName)s have \(legCount) legs")
}
// repeat-while 循环的个别格局
repeat {statements} while condition
// 提前退出
func greet(person: [String: String]) {guard let name = person["name"] else {return}
print("Hello \(name)!")
guard let location = person["location"] else {print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(person: ["name": "John"])
// 输入“Hello John!”// 输入“I hope the weather is nice near you.”greet(person: ["name": "Jane", "location": "Cupertino"])
// 输入“Hello Jane!”// 输入“I hope the weather is nice in Cupertino.”
函数
函数的定义与调用,函数参数与返回值,函数参数标签和参数名称,函数类型,嵌套函数
可选元组返回类型。
定义一个输入输出参数时,在参数定义前加 inout 关键字。
示例:
// 函数
func greet(person: String) -> String {
let greeting = "Hello," + person + "!"
return greeting
}
func greet(person: String, from hometown: String) -> String {return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// 打印“Hello Bill! Glad you could visit from Cupertino.”// 可选元组返回类型
func minMax(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)
}
// 隐式返回的函数
func greeting(for person: String) -> String {"Hello," + person + "!"}
print(greeting(for: "Dave"))
// 打印 "Hello, Dave!
// 参数标签
func greet(person: String, from hometown: String) -> String {return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// 打印“Hello Bill! Glad you could visit from Cupertino.”
函数
函数的定义与调用,函数参数与返回值,函数参数标签和参数名称,函数类型,嵌套函数
可选元组返回类型。
定义一个输入输出参数时,在参数定义前加 inout 关键字。
示例:
// 函数
func greet(person: String) -> String {
let greeting = "Hello," + person + "!"
return greeting
}
func greet(person: String, from hometown: String) -> String {return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// 打印“Hello Bill! Glad you could visit from Cupertino.”// 可选元组返回类型
func minMax(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)
}
// 隐式返回的函数
func greeting(for person: String) -> String {"Hello," + person + "!"}
print(greeting(for: "Dave"))
// 打印 "Hello, Dave!
// 参数标签
func greet(person: String, from hometown: String) -> String {return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// 打印“Hello Bill! Glad you could visit from Cupertino.”
闭包
闭包是自蕴含的函数代码块,能够在代码中被传递和应用。与一些编程语言中的匿名函数(Lambdas)比拟类似。
闭包表达式,尾随闭包,值捕捉,闭包是援用类型,逃逸闭包(@escaping),主动闭包
如果你须要将一个很长的闭包表达式作为最初一个参数传递给函数,将这个闭包替换成为尾随闭包的模式很有用。
闭包能够在其被定义的上下文中捕捉常量或变量。即便定义这些常量和变量的原作用域曾经不存在,闭包依然能够在闭包函数体内援用和批改这些值。
示例:
// 闭包表达式语法
{(parameters) -> return type in
statements
}
// 尾随闭包
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
}
// strings 常量被推断为字符串类型数组,即 [String]
// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]
// 值捕捉
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
// 主动闭包,提早求值
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// 打印出“5”let customerProvider = {customersInLine.remove(at: 0) }
print(customersInLine.count)
// 打印出“5”print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// 打印出“4”
枚举
应用 enum 关键词来创立枚举并且把它们的整个定义放在一对大括号内。
枚举语法,应用 Switch 语句匹配枚举值,枚举成员的遍历,关联值,原始值(默认值),递归枚举(indirect)
能够定义 Swift 枚举来存储任意类型的关联值,每个枚举成员的关联值类型能够各不相同。
示例:
// 枚举语法
enum SomeEnumeration {// 枚举定义放在这里}
enum CompassPoint {
case north
case south
case east
case west
}
enum Planet {case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune}
let somePlanet = Planet.earth
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
// 打印“Mostly harmless”// 关联值
enum Barcode {case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
switch productBarcode {case let .upc(numberSystem, manufacturer, product, check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
print("QR code: \(productCode).")
}
// 打印“QR code: ABCDEFGHIJKLMNOP.”// 递归枚举
indirect enum ArithmeticExpression {case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
// (5 + 4) * 2
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
print(evaluate(product))
// 打印“18”
构造体和类
构造体和类比照,构造体和枚举是值类型,类是援用类型
构造体和类作为一种通用而又灵便的构造,成为了人们构建代码的根底。你能够应用定义常量、变量和函数的语法,为你的构造体和类定义属性、增加办法。
示例:
// 类和构造体
struct SomeStructure {// 在这里定义构造体}
class SomeClass {// 在这里定义类}
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
属性
存储属性,计算属性,属性观察器,属性包装器,全局变量和局部变量,类型属性(static)
属性将值与特定的类、构造体或枚举关联。存储属性会将常量和变量存储为实例的一部分,而计算属性则是间接计算(而不是存储)值。计算属性能够用于类、构造体和枚举,而存储属性只能用于类和构造体。
属性观察器监控和响应属性值的变动,每次属性被设置值的时候都会调用属性观察器,即便新值和以后值雷同的时候也不例外。
willSet 在新的值被设置之前调用
didSet 在新的值被设置之后调用
属性包装器在治理属性如何存储和定义属性的代码之间增加了一个分隔层。
类型属性也是通过点运算符来拜访。然而,类型属性是通过类型自身来拜访,而不是通过实例。
示例:
// 属性
struct Point {var x = 0.0, y = 0.0}
struct Size {var width = 0.0, height = 0.0}
struct Rect {var origin = Point()
var size = Size() // 存储属性
var center: Point { // 计算型属性
get {let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 打印“square.origin is now at (10.0, 10.0)”// 属性包装器
@propertyWrapper
struct TwelveOrLess {
private var number = 0
var wrappedValue: Int {get { return number}
set {number = min(newValue, 12) }
}
}
办法
实例办法(Instance Methods),类型办法(static)
办法是与某些特定类型相关联的函数。
类、构造体、枚举都能够定义实例办法;实例办法为给定类型的实例封装了具体的工作与性能。
类、构造体、枚举也能够定义类型办法;类型办法与类型自身相关联。
示例:
// 办法
class Counter {
var count = 0
func increment() {count += 1}
func increment(by amount: Int) {count += amount}
func reset() {count = 0}
}
下标
下标能够定义在类、构造体和枚举中,是拜访汇合、列表或序列中元素的快捷方式
下标语法(subscript),下标用法,下标选项,类型下标(static)
subscript(index: Int) -> Int {
get {// 返回一个适当的 Int 类型的值}
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])")
// 打印“six times three is 18”var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
// 类型下标
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
static subscript(n: Int) -> Planet {return Planet(rawValue: n)!
}
}
let mars = Planet[4]
print(mars)
继承
定义一个基类,子类生成,重写 (override),避免重写(final)
不继承于其它类的类,称之为基类。
示例:
// 继承
class SomeClass: SomeSuperclass {// 这里是子类的定义}
class Vehicle {
var currentSpeed = 0.0
var description: String {return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {// 什么也不做——因为车辆不肯定会有乐音}
}
class Car: Vehicle {
var gear = 1
override var description: String {return super.description + "in gear \(gear)"
}
}
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {gear = Int(currentSpeed / 10.0) + 1
}
}
}
结构过程
结构过程是应用类、构造体或枚举类型的实例之前的筹备过程。
存储属性的初始赋值,自定义结构过程,默认结构器,值类型的结构器代理,类的继承和结构过程,可失败结构器,必要结构器(required)
结构器能够通过调用其它结构器来实现实例的局部结构过程。这一过程称为结构器代理,它能防止多个结构器间的代码反复。
Swift 为类类型提供了两种结构器来确保实例中所有存储型属性都能取得初始值,它们被称为指定结构器和便当结构器。
能够在一个类,构造体或是枚举类型的定义中,增加一个或多个可失败结构器。其语法为在 init 关键字前面增加问号(init?)。
必要结构器,在类的结构器前增加 required 修饰符表明所有该类的子类都必须实现该结构器。
示例:
// 结构过程
init() {// 在此处执行结构过程}
struct Fahrenheit {
var temperature: Double
init() {temperature = 32.0}
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// 打印“The default temperature is 32.0° Fahrenheit”struct Color {
let red, green, blue: Double
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
init(white: Double) {
red = white
green = white
blue = white
}
}
析构过程
析构器只实用于类类型,当一个类的实例被开释之前,析构器会被立刻调用。析构器用关键字 deinit 来标示,相似于结构器要用 init 来标示。
Swift 会主动开释不再须要的实例以开释资源。
示例:
// 析构过程
deinit {// 执行析构过程}
class Bank {
static var coinsInBank = 10_000
static func distribute(coins numberOfCoinsRequested: Int) -> Int {let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receive(coins: Int) {coinsInBank += coins}
}
class Player {
var coinsInPurse: Int
init(coins: Int) {coinsInPurse = Bank.distribute(coins: coins)
}
func win(coins: Int) {coinsInPurse += Bank.distribute(coins: coins)
}
deinit {Bank.receive(coins: coinsInPurse)
}
}
可选链式调用
可选链式调用是一种能够在以后值可能为 nil 的可选值上申请和调用属性、办法及下标的办法。
通过在想调用的属性、办法,或下标的可选值前面放一个问号(?),能够定义一个可选链。相似在可选值前面放一个叹号(!)来强制开展它的值。它们的次要区别在于当可选值为空时可选链式调用只会调用失败,然而强制开展将会触发运行时谬误。
示例:
class Person {var residence: Residence?}
class Residence {var numberOfRooms = 1}
let john = Person()
let roomCount = john.residence!.numberOfRooms
// 这会引发运行时谬误
if let roomCount = john.residence?.numberOfRooms {print("John's residence has \(roomCount) room(s).")
} else {print("Unable to retrieve the number of rooms.")
}
// 打印“Unable to retrieve the number of rooms.”john.residence = Residence()
if let roomCount = john.residence?.numberOfRooms {print("John's residence has \(roomCount) room(s).")
} else {print("Unable to retrieve the number of rooms.")
}
// 打印“John's residence has 1 room(s).”
错误处理
错误处理(Error handling)是响应谬误以及从谬误中复原的过程。Swift 在运行时提供了抛出、捕捉、传递和操作可复原谬误(recoverable errors)的一等反对。
示意与抛出谬误,处理错误,指定清理操作
在 Swift 中,谬误用遵循 Error 协定的类型的值来示意。
Swift 中有 4 种处理错误的形式。能够把函数抛出的谬误传递给调用此函数的代码(throws)、用 do-catch 语句处理错误、将谬误作为可选类型解决(try?)、或者断言此谬误基本不会产生(try!)。
defer 语句将代码的执行提早到以后的作用域退出之前。
示例:
// 错误处理
enum VendingMachineError: Error {
case invalidSelection // 抉择有效
case insufficientFunds(coinsNeeded: Int) // 金额有余
case outOfStock // 缺货
}
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
print("Success! Yum.")
} catch VendingMachineError.invalidSelection {print("Invalid Selection.")
} catch VendingMachineError.outOfStock {print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
} catch {print("Unexpected error: \(error).")
}
// 打印“Insufficient funds. Please insert an additional 2 coins.”// 指定清理操作
func processFile(filename: String) throws {if exists(filename) {let file = open(filename)
defer {close(file)
}
while let line = try file.readline() {// 解决文件。}
// close(file) 会在这里被调用,即作用域的最初。}
}
类型转换
类型转换在 Swift 中应用 is 和 as 操作符实现。这两个操作符别离提供了一种简略达意的形式去查看值的类型或者转换它的类型。
为类型转换定义类档次,查看类型(is),向下转型(as? 或 as!),Any 和 AnyObject 的类型转换
能够将类型转换用在类和子类的层次结构上,查看特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其余类型。
Swift 为不确定类型提供了两种非凡的类型别名:
Any 能够示意任何类型,包含函数类型。
AnyObject 能够示意任何类类型的实例。
示例:
// 类型转换
// 一个基类 MediaItem
class MediaItem {
var name: String
init(name: String) {self.name = name}
}
class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.srtist = artist
super.init(name: name)
}
}
let library = [Movie(name: "Casablanca", director: "Micheal Curtiz"),
Song(name: "Blue Suede Shose", artist: "Elvis Presley"),
Movie(name: "Citizen Kane", director: "Orson Wells"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
var movieCount = 0
var songCount = 0
for item in library {
if item is Movie {movieCount += 1} else if item is Song {songCount += 1}
}
print("Media library contains \(movieCount) movies and \(songCount)")
// 打印“Media library contains 2 movies and 3 songs”for item in library {
if let movie = item as? Movie {print("Movie: \(movie.name), dir. \(movie.director)")
} else if let song = item as? Song {print("Song: \(song.name), by \(song.artist)")
}
}
// Movie: Casablanca, dir. Michael Curtiz
// Song: Blue Suede Shoes, by Elvis Presley
// Movie: Citizen Kane, dir. Orson Welles
// Song: The One And Only, by Chesney Hawkes
// Song: Never Gonna Give You Up, by Rick Astley
嵌套类型
Swift 容许定义嵌套类型,能够在反对的类型中定义嵌套的枚举、类和构造体。
嵌套类型实际,援用嵌套类型
要在一个类型中嵌套另一个类型,将嵌套类型的定义写在其内部类型的 {} 内,而且能够依据须要定义多级嵌套。
示例:
// 嵌套类型
stuct BlackjackCard {
// 嵌套的 Suit 枚举
enum Suit: Character {case spades = "1", hearts = "2", diamonds = "3", clubs = "4"}
// 嵌套的 Rank 枚举
enum Rank: Int {
case two = 2, three, four, five, six, seven, eight, nine, ten
case jack, queen, king, ace
struct Values {let first: Int, second: Int?}
var values: Values {
switch self {
case .ace:
return Values(first: 1, second: 11)
case .jack, .queen, .king:
return Values(first: 10, second: nil)
default:
return Values(first: self.rawValue, second: nil)
}
}
}
// BlackjackCard 的属性和办法
let rank: Rank, suit: Suit
var description: String {var output = "suit is \(suit.rawValue),"
output += "value is \(rank.values.first)"
if let second = rank.values.second {output += "or \(second)"
}
return output
}
}
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// 打印“theAceOfSpades: suit is 1, value is 1 or 11”let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// 2
扩大
扩大能够给一个现有的类,构造体,枚举,还有协定增加新的性能。
扩大的语法,计算型属性,结构器,办法,下标,嵌套类型
Swift 中的扩大能够:
增加计算型实例属性和计算型类属性
定义实例办法和类办法
提供新的结构器
定义下标
定义和应用新的嵌套类型
使曾经存在的类型遵循(conform)一个协定
扩大语法:
extension SomeType {// 在这里给 SomeType 增加新的性能}
扩大能够给现有类型增加计算型实例属性和计算型类属性。
扩大能够给现有的类型增加新的结构器。
扩大能够给现有类型增加新的实例办法和类办法。
扩大能够给现有的类型增加新的下标。
扩大能够给现有的类,构造体,还有枚举增加新的嵌套类型。
示例:
// 扩大的语法
extension SomeType {// 在这里给 SomeType 增加新的性能}
// 增加一个或多个协定
extension SomeType: SomeProtocol, AnotherProtocol {// 协定所须要的实现写在这里}
struct Size {var width = 0.0, height = 0.0}
struct Point {var x = 0.0, y = 0.0}
struct Rect {var origin = Point()
var size = Size()}
extension Rect {init(center: Point, size: Size) {let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 3)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect 的 origin 是 (2.5, 2.5) 并且它的 size 是 (3.0, 3.0)
extension Int {func repetitions(task: () -> Void) {
for _ in 0..<self {task()
}
}
}
3.repetitions {print("Hello!")
}
// Hello!
// Hello!
// Hello!
extension Int {mutating func square() {self = self * self}
}
var somtInt = 3
someInt.square()
// someInt 当初是 9
协定
协定定义了一个蓝图,规定了用来实现某一特定工作或者性能的办法、属性,以及其余须要的货色。
类、构造体或枚举都能够遵循协定,并为协定定义的这些要求提供具体实现。
协定语法,属性要求,办法要求,异变办法要求,结构器要求,协定作为类型,委托,协定类型的汇合,协定的继承,类专属的协定,协定合成,查看协定一致性,可选的协定要求,协定扩大,
协定语法
protocol SomeProtocol {// 这里是协定的定义局部}
协定能够要求遵循协定的类型提供特定名称和类型的实例属性或类型属性。
协定能够要求遵循协定的类型实现某些指定的实例办法或类办法。
在值类型(即构造体和枚举)的实例办法中,将 mutating 关键字作为办法的前缀,写在 func 关键字之前,示意能够在该办法中批改它所属的实例以及实例的任意属性的值。
协定能够要求遵循协定的类型实现指定的结构器。
委托是一种设计模式,它容许类或构造体将一些须要它们负责的性能委托给其余类型的实例。
示例:
// 协定语法
protocol SomeProtocol {// 这里是协定的定义局部}
struct SomeStructure: FirstProtocol, AnotherProtocol {// 这里是构造体的定义局部}
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {// 这里是类的定义局部}
protocol SomeProtocol {var mustBeSettable: Int { get set}
var doesNotNeedToBeSettable: Int {get}
}
protocol AnotherProtocol {static var someTypeProperty: Int { get set}
}
protocol FullyNamed {var fullName: String { get}
}
struct person: FullyNamed {var fullName: String}
let john = Person(fullName: "John Appleseed")
// john.fullName 为 "John Appleseed"
class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {return (prefix != nil ? prefix! + "" :"") + name
}
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName 为 "USS Enterprise"
泛型
泛型代码让你能依据自定义的需要,编写出实用于任意类型的、灵便可复用的函数及类型。
你可防止编写反复的代码,而是用一种清晰形象的形式来表白代码的用意。
泛型函数,类型参数,命名类型参数,泛型类型,泛型扩大,类型束缚,关联类型
示例:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoInts(_ a: inout Int, _ b: inout Int)
func swapTwoValues<T>(_ a: inout T, _ b: inout T)
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt 当初是 107,anotherInt 当初是 3
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString 当初是“world”,anotherString 当初是“hello”
不通明类型
具备不通明返回类型的函数或方 * 暗藏返回值的类型信息。
函数不再提供具体的类型作为返回类型,而是依据它反对的协定来形容返回值。
不通明类型解决的问题,返回不通明类型,不通明类型和协定类型的区别
在解决模块和调用代码之间的关系时,暗藏类型信息十分有用,因为返回的底层数据类型依然能够放弃公有。
不通明类型和泛型相同。不通明类型容许函数实现时,抉择一个与调用代码无关的返回类型。
如果函数中有多个中央返回了不通明类型,那么所有可能的返回值都必须是同一类型。返回不通明类型和返回协定类型次要区别,就在于是否须要保障类型一致性。
一个不通明类型只能对应一个具体的类型,即使函数调用者并不能晓得是哪一种类型;协定类型能够同时对应多个类型,只有它们都遵循同一协定。
示例:
protocol Shape {func draw() -> String
}
struct Triangle: Shape {
var size: Int
func draw() -> String {var result = [String]()
for length in 1...size {result.append(String(repeating: "*", count: length))
}
return result.joined(separator: "\n")
}
}
let smallTriangle = Triangle(size: 3)
print(smallTriangle.draw())
// *
// **
// ***
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
let flippedTriangle = FlippedShape(shape: smallTriangle)
print(flippedTriangle.draw())
// ***
// **
// *
主动援用计数
Swift 应用主动援用计数(ARC)机制来跟踪和治理你的应用程序的内存。
如果两个类实例相互持有对方的强援用,因此每个实例都让对方始终存在,就是这种状况。这就是所谓的循环强援用。
Swift 提供了两种方法用来解决你在应用类的属性时所遇到的循环强援用问题:弱援用(weak reference)和无主援用(unowned reference)。
申明属性或者变量时,在后面加上 weak 关键字表明这是一个弱援用。
申明属性或者变量时,在后面加上关键字 unowned 示意这是一个无主援用。
示例:
// 主动援用计数实际
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {print("\(name) is being deinitialized")
}
}
var reference1: Person?
var reference2: Person?
var reference3: Person?
reference1 = Person(name: "John Appleseed")
// 打印“John Appleseed is being initialized”reference2 = reference1
reference3 = reference1
reference1 = nil
reference2 = nil
reference3 = nil
// 打印“John Appleseed is being deinitialized”// 循环强援用
class Person {
let name: String
init(name: String) {self.name = name}
var apartment: Apartment?
deinit {print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) {self.unit = unit}
var tenant: Person?
deinit {print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john = nil
unit4A = nil
// 弱援用
class Person {
let name: String
init(name: String) {self.name = name}
var apartment: Apartment?
deinit {print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) {self.unit = unit}
weak var tenant: Person?
deinit {print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
// 打印“John Appleseed is being deinitialized”
内存平安
默认状况下,Swift 会阻止你代码里不平安的行为。
了解内存拜访抵触,In-Out 参数的拜访抵触,办法里 self 的拜访抵触,属性的拜访抵触
示例:
func balance(_ x: inout Int, _ y: inout Int) {
let sum = x + y
x = sum / 2
y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore) // 失常
balance(&playerOneScore, &playerOneScore)
// 谬误:playerOneScore 拜访抵触
访问控制
访问控制能够限定其它源文件或模块对你的代码的拜访。
open 和 public 级别能够让实体被同一模块源文件中的所有实体拜访,在模块外也能够通过导入该模块来拜访源文件里的所有实体。通常状况下,你会应用 open 或 public 级别来指定框架的内部接口。
internal 级别让实体被同一模块源文件中的任何实体拜访,然而不能被模块外的实体拜访。通常状况下,如果某个接口只在应用程序或框架外部应用,就能够将其设置为 internal 级别。
fileprivate 限度实体只能在其定义的文件外部拜访。如果性能的局部实现细节只须要在文件内应用时,能够应用 fileprivate 来将其暗藏。
private 限度实体只能在其定义的作用域,以及同一文件内的 extension 拜访。如果性能的局部细节只须要在以后作用域内应用时,能够应用 private 来将其暗藏。
open 为最高拜访级别(限度起码),private 为最低拜访级别(限度最多)。
open 只能作用于类和类的成员,它和 public 的区别次要在于 open 限定的类和成员可能在模块外能被继承和重写。
示例:
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
class SomeInternalClass {} // 隐式 internal
var someInternalConstant = 0 // 隐式 internal
public class SomePublicClass { // 显式 public 类
public var somePublicProperty = 0 // 显式 public 类成员
var someInternalProperty = 0 // 隐式 internal 类成员
fileprivate func someFilePrivateMethod() {} // 显式 fileprivate 类成员
private func somePrivateMethod() {} // 显式 private 类成员
}
class SomeInternalClass { // 隐式 internal 类
var someInternalProperty = 0 // 隐式 internal 类成员
fileprivate func someFilePrivateMethod() {} // 显式 fileprivate 类成员
private func somePrivateMethod() {} // 显式 private 类成员
}
fileprivate class SomeFilePrivateClass { // 显式 fileprivate 类
func someFilePrivateMethod() {} // 隐式 fileprivate 类成员
private func somePrivateMethod() {} // 显式 private 类成员
}
private class SomePrivateClass { // 显式 private 类
func somePrivateMethod() {} // 隐式 private 类成员
}
高级运算符
Swift 还提供了数种能够对数值进行简单运算的高级运算符。它们蕴含了位运算符和移位运算符。
位运算符、溢出运算符、优先级和联合性、运算符函数、自定义运算符
示例:
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // 等于 0b11110000
var potentialOverflow = Int16.max
// potentialOverflow 的值是 32767,这是 Int16 能包容的最大整数
potentialOverflow += 1
// 这里会报错
struct Vector2D {var x = 0.0, y = 0.0}
extension Vector2D {static func + (left: Vector2D, right: Vector2D) -> Vector2D {return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
}
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector 是一个新的 Vector2D 实例,值为 (5.0, 5.0)
最初有什么纳闷问题这有个 iOS 交换群:642363427 有一个独特的圈子很重要,结识人脉!外面都是 iOS 开发,全栈倒退,欢送入驻,共同进步!(群内会收费提供一些群主珍藏的收费学习书籍材料以及整顿好的几百道面试题和答案文档!)