Swift基础知识
最近闲来无事,准备花一周时间来整理一下Swift中的相关知识,这里整理的主要是Swift官方文档的内容及自己的一些认识,有什么不准确的地方,欢迎大家指正。
这一章主要讲Swift的基础知识,旨在让大家对Swift有一个整体的了解,之后后详细的介绍各个部分的详细内容。
定义常量和变量
Swift中,只用let关键字来定义一个常量,使用var关键字来定义一个变量。
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
你也可以在一行中定义多个常量或多个变量,使用逗号分隔。
var x = 0.0, y = 0.0, z = 0.0
总结:
- 一条Swift语句,不必以分号作为结尾。
- Swift是类型安全的语言。
- 如果存储的值不需要改变,使用let关键字将其定义为常量。如果存储的值需要改变,使用var关键字将其定义为变量。
类型注释
可以通过类型注释的方式,来清晰的指定你定义的常量或变量所能存储的值的类型。
var welcomeMessage: String
welcomeMessage = "Hello"
上面这段代码可以读为:定义一个String类型的变量。
你可以在一行定义多个常量或变量,通过逗号分隔,然后使用一个类型注释来标注它们。
var red, green, blue: Double
总结:
- 在使用类型注释时,注意冒号后要有一个空格。
- 在实际开发中。类型注释用的很少。如果在定义时指定初始值,Swift可以根据初始值来推断出变量/常量的类型。如果不指定初始值,则需要类型注释来指定变量/常量所能存储的值的类型。
- 一旦常量/变量的类型确定了,它所存储的值的类型也就确定了。
变量和常量的命名
几乎可以使用任意字符来命名变量和常量,包括Unicode字符:
let π = 3.14159
let 你好 = "你好世界"
常量和变量的名称不能包括:空白字符,数学符号,箭头,私有的(或无用的)码点,或-。
总结:
如果需要使用Swift预留的关键字来命名常量/变量,在变量前后加`来解决。除非没有选择,否则不要使用预留关键字来命名。
var `var` = 123
注释
- 单行注释:
// This is a comment.
- 多行注释:
/* This is also a comment
but is written over multiple lines. */
- 嵌套的多行注释:(Swift中新增的)
/* This is the start of the first multiline comment.
/* This is the second, nested multiline comment. */
This is the end of the first multiline comment. */
分号
不像其它语言,Swift中每条语句的末尾分号不是必须的。如果在一行中写多条语句,则分号是必须的。
let cat = "cat"; print(cat)
// Prints "cat"
整型
Swift提供了8,16,32和64位的有符号和无符号整型。分别为Int8/UInt8,Int16/UInt16,Int32/UInt32,Int64/UInt64。
整数范围
可以使用每个整数类型的min和max来访问最大和最小值。
let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
Int
大多数情况下,你不需要在代码中选择特定大小的整数类型,这时候可以使用Int类型,Int类型的大小和当前平台的位数保持一致。
- 在32位的平台上,Int同Int32。
- 在64位的平台上,Int同Int64。
UInt
无符号整型。和当前平台的位数保持一致。
- 在32位的平台上,UInt同UInt32。
- 在64位的平台上,UInt同UInt64。
浮点数
Double代表64位浮点数。
Float代表32位浮点数。
总结:
- Double至少要有15位的精度,而FLoat至少6位的精度。
类型安全和类型推断
Swift是一门类型安全的语言。所谓类型安全的语言,就是你要清楚你所使用的值类型。如果需要一个String类型的值,如果传递Int类型,就会产生错误。
因为Swift是类型安全的,会在编译的时候进行类型检查,并且将不匹配的类型标记为错误。可以使你尽早的在开发过程中发现错误。
在定义常量/变量时,并不需要必须指明其类型。如果在定义时没有指明类型,Swift会使用类型推断来帮助你确定合适的类型。类型推断使编译器只需检查所提供的值,就可以自动推断指定表达式的类型。
在定义一个带有初始值的常量/变量时,类型推断是非常有用的。
let meaningOfLife = 42 //meaningOfLife被推断为是Int型
let pi = 3.14159 //pi被推断为是Double类型
let anotherPi = 3 + 0.14159 //anotherPi被推断为Double类型
数值型的字面值
数值型的字面值包括:
- 无前缀的十进制。
- 以0b开头的二进制。
- 以0o开头的八进制。
- 以0x开头的十六进制。
let decimalInteger = 17 // 17的十进制表示
let binaryInteger = 0b10001 // 17的二进制表示
let octalInteger = 0o21 // 17的八进制表示
let hexadecimalInteger = 0x11 // 17的十六进制表示
所有这些字面值,都对应十进制中的17。
浮点型的字面值包括:无前缀的十进制和带有0x前缀的十六进制。十进制通过e/E指定指数,以10为底,十六进制通过p/P指定指数,以2为底。
- 1.25e2相当于1.25 * 10²,或125.0。
- 1.25e﹣²相当于1.25 * 10﹣², 或0.0125。
- 0xFp2相当于15 * 2²,或60。
- 0xFp﹣²相当于14 * 2﹣²,或3.75.
数值型字面值可以包含额外的格式,使它们更容易阅读。
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
数值类型转换
数值型类型转换的格式是:SomeType(ofInitialValue),这种方式相当于调用SomeType的初始化方法,新创建一个SomeType类型的实例。
整数类型间转换
直接看例子:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
整数和浮点数间转换
直接看例子:
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
let integerPi = Int(pi) //integerPi的值为3
总结:
- Swift中的类型转换同Objective-C不同,类型兼容的类型间转换也要显示使用SomeType(ofInitialValue)这种形式进行转换。
类型别名
类型别名是为已存在的类型定义一个可选的名字。使用typealias关键字来为类型定义别名。
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
布尔值
Swift中使用Bool来指定布尔值。Swift只存在两个布尔类型的常量。true和false。
let orangesAreOrange = true
let turnipsAreDelicious = false
Swift是类型安全的语言,因此不可以将非布尔值来代替布尔值。
let i = 1
if i {
//编译时会报错
}
let i = 1
if i == 1 {
// 会成功编译
}
元组
元组是Swift中新增的概念,是将多个值合成一个单一的值。元组中的各个值不必是相同类型。
let http404Error = (404, "Not Found")
//http404Error是(Int, String)类型
访问元组
- 将元组中的内容分解为独立的常量/变量,然后按通常的方式来访问:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
//输出: "The status code is 404"
print("The status message is \(statusMessage)")
//输出: "The status message is Not Found"
如果只需要元组中的部分值,元组中忽略的部分可以用下划线(_)代替
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
//输出: "The status code is 404"
- 使用下标的方式来访问元组中的值:
print("The status code is \(http404Error.0)")
//输出: "The status code is 404"
print("The status message is \(http404Error.1)")
//输出: "The status message is Not Found"
- 前提:定义元组时,为元组中的单个元素命名。可以使用元素名称来访问元组中的元素:
print("The status code is \(http200Status.statusCode)")
//输出: "The status code is 200"
print("The status message is \(http200Status.description)")
//输出: "The status message is OK"
总结:
- 元组在作为函数返回值时,是非常有用的。
- 元组不适用于创建复杂的数据结构,它仅对多个相关值临时组合在一起是有用的。
可选类型
Swift中新增的概念。如果一个值有可能不存在,那么就使用可选类型。一个可选类型包括两种可能性:一是有值,你需要解包来访问这个值。二是压根就无值。
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
//convertedNumber被推断为"Int?",或可选Int类型
因为Int()初始化方法有肯呢个失败,所以它返回的是可选的Int类型,写成Int?。使用问号(?)来指定它包含的值是可选的。
nil
nil指定一个常量/变量不包含任何值。
var serverResponseCode: Int? = 404
// serverResponseCode 包含一个实际的值404
serverResponseCode = nil
// serverResponseCode 此时不包含任何值
如果定义一个未提供默认值的可选变量,这个可选变量会被自动设置为nil
var surveyAnswer: String?
// surveyAnswer 被自动设置为nil
if语句和强制解包
通过将可选值同nil对比来确定可选值是否包含一个值,使用==操作符和!=操作符来实现。
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
//输出: "convertedNumber contains some integer value."
一旦确定了可选值有值,则可以通过在可选变量/常量后加感叹号(!)来访问这个值,意思是:我完全确定这个可选值有值;请放心的使用。这就是所谓的强制解包:
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
//输出: "convertedNumber has an integer value of 123."
可选绑定
使用可选绑定来确认可选变量/常量是否包含一个值,如果包含,将其赋值给一个临时的常量/变量。
if let constantName = someOptional {
statements
}
if let actualNumber = Int(possibleNumber) {
print("\"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
print("\"\(possibleNumber)\" could not be converted to an integer")
}
//输出: ""123" has an integer value of 123"
可以在条件语句中使用任意多个可选绑定和Bool值,使用逗号(,)分隔。如果任意的可选绑定是nil或任意的布尔值是false,则整个条件语句为false。
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
//输出: "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
//输出: "4 < 42 < 100"
隐式解包的可选类型
直接看例子:
let possibleString: String? = "An optional string."
let forcedString: String = possibleString!
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString
使用隐式解包的前提是:确定该可选变量/常量有值。定义时,在类型后面加!来指定该变量/常量已隐式解包,后面如果在使用这个变量/常量就不用在强制解包了。
总结:
- Swift中的nil和Objective-C中的nil不同,Swift中的nil不是一个指针,它只代表特定类型的缺失值,任何类型都可以被设置为nil。
- 如果在不存在的可选值后使用!,会造成运行时错误。
- 在if和while语句中使用可选绑定。
错误处理
使用错误处理来响应程序执行过程中可能遇见的错误条件。
- 抛出错误,通过throws关键字:
func canThrowAnError() throws {
// 这个函数有可能会抛出一个错误
}
- 捕获错误,通过catch关键字:
do {
try canThrowAnError()
// no error was thrown
} catch {
// an error was thrown
}
- 错误的处理流程:
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
断言
在某些情况下,如果不满足某个条件,程序就不能执行下去,这时候可以使用断言来终止程序的执行并调试。
什么时候使用断言
如果条件有可能是false,但要求必须是true,这时候使用断言。断言检测的场景包括:
- 索引越界。
- 无效的函数参数。
- 一个可选类型必须有值的时候才能继续执行。
总结:
- 断言是发现程序中不合法值的一种有效方式。