Published 2022-03-01

Swift - 基础知识

Swift 是一种适用于 iOS、macOS、watchOS 和 Apple tvOS app 开发的新编程语言。尽管如此,Swift的许多部分将从您在C和Objective-C中开发的经验中熟悉。

Swift提供所有基本C和Objective-C类型的版本,包括用于整数的Int、用于浮点值的Double和Float、用于布尔值的Bool和用于文本数据的String。Swift还提供了三种主要集合类型的强大版本,例如Array、Set和Dictionary,如Collection Types中所述。

与C一样,Swift使用变量通过标识名称存储和引用值。Swift还广泛使用其值无法更改的变量。这些被称为常数,比C中的常数强大得多。当您处理不需要更改的值时,整个Swift都使用常量,以使代码的意图更安全、更清晰。

除了熟悉的类型外,Swift还引入了Objective-C中没有的高级类型,例如元组。元组使您能够创建和传递值分组。您可以使用元组将函数中的多个值作为单个复合值返回。

Swift还引入了可选类型,用于处理缺少值的情况。可选的说“有一个值,它等于x”或“根本没有值”。使用可选选项类似于在Objective-C中使用带有指针的nil,但它们适用于任何类型,而不仅仅是类。可选选项不仅比Objective-C中的nil指针更安全、更具表现力,而且是Swift许多最强大功能的核心。

Swift是一种类型安全的语言,这意味着该语言可以帮助您清楚地了解代码可以使用的值类型。如果您的部分代码需要String,类型安全性会阻止您错误地将其传递给Int。同样,类型安全可防止您意外地将可选String传递给需要非可选String的代码。类型安全可帮助您尽早在开发过程中捕获和修复错误。

常量和变量

常量和变量将值分配给特定的标识符,以便您可以在代码中引用它们。常量的值一旦设置就无法更改,而变量的值可以更改。

声明常量和变量

您可以使用let关键字声明常量,使用var关键字声明变量。常量和变量的名称可以包含任何字符,包括Unicode字符:

let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0

常量和变量的名称不能包含空格、数学符号、箭头、保留的(或者非法的)Unicode代码点、连线和制表符。也不能以数字开头,但可以在名称的其他地方包含数字。

打印常量和变量的值:

print(maximumNumberOfLoginAttempts)
print(currentLoginAttempt)

使用反斜杠(\)将常量和变量的名称放在括号中,以在字符串插值中包含它们的当前值:

print("Maximum number of login attempts is \(maximumNumberOfLoginAttempts)")

类型标注

您可以在声明常量或变量时提供类型标注(type annotation),以明确常量或变量可以存储的值的类型。在类型标注后面加上一个冒号和空格,然后加上类型名称,以指定常量或变量可以存储的值的类型:

var welcomeMessage: String

类型标注是一种为常量或变量提供关于其允许存储的值类型的方法。它不会为常量或变量的值分配任何实际的值;它只是说明了常量或变量可以存储的值的类型。如果您在声明常量或变量时提供了类型标注,您可以在该常量或变量的赋值语句中省略对其类型的说明。类型标注的使用可以使您的代码更具可读性,因为它允许您立即知道常量或变量可以存储的值的类型。

注释

您可以使用单行注释(single-line comments)将注释嵌入到代码中。单行注释以两个正斜杠(//)开头:

// This is a comment

您可以使用多行注释(multi-line comments)将注释嵌入到代码中。多行注释以正斜杠后跟星号(/)开头,以星号后跟正斜杠(/)结尾:

/* This is also a comment
but is written over multiple lines. */

分号

Swift不要求您在每个语句结尾处使用分号(;),但是您可以使用分号将多个独立的语句写在同一行上:

let cat = "🐱"; print(cat)

整数

整数是没有小数部分的数字,例如42和-23。Swift提供了8、16、32和64位有符号和无符号整数类型。这些整数类型的名称与它们的位数相同,例如UInt8表示8位无符号整数,Int32表示32位有符号整数。

整数范围:

let minValue = UInt8.min
let maxValue = UInt8.max

浮点数

浮点数是有小数部分的数字,例如3.14159、0.1和-273.15。Swift提供了两种有符号的浮点数类型:

如果您需要在您的代码中选择浮点数类型,推荐使用Double类型,除非你特别需要它的性能。

类型安全和类型推断

Swift是一种类型安全(type-safe)语言。类型安全语言可以让您清楚地知道代码可以处理的值的类型。如果部分代码期望得到String,您就不能传递一个Int来代替。

Swift通过类型推断(type inference)来选择合适的类型。如果您没有明确指定类型,Swift使用类型推断来选择合适的类型。例如,如果您给一个新的浮点值赋值,Swift会推断您想要创建一个Double而不是Float:

let meaningOfLife = 42
// meaningOfLife is inferred to be of type Int
let pi = 3.14159
// pi is inferred to be of type Double

如果您在一行中声明多个同类型的值,您可以在一行中写出所有值,用逗号隔开,Swift会自动推断出这些值的类型:

let x = 0.0, y = 0.0, z = 0.0

数值型字面量

整数字面量可以被写作:

十进制数的例子:

let decimalInteger = 17
let binaryInteger = 0b10001       // 17 in binary notation
let octalInteger = 0o21           // 17 in octal notation
let hexadecimalInteger = 0x11     // 17 in hexadecimal notation

浮点字面量可以是十进制(没有前缀),或者是十六进制(前缀是0x)。十进制浮点字面量还可以有一个可选的指数(exponent),通过大写或小写的e来指定。十六进制浮点字面量必须有一个指数;指数通过大写或小写的p来指定。十进制浮点字面量的例子:

let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0

数值型类型转换

整数和浮点数类型转换必须显式指定类型:

let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
// twoThousandAndOne is equal to 2001

类型别名

类型别名(type aliases)就是给现有类型定义另一个名字。你可以使用typealias关键字来定义类型别名。

typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0

布尔值

Swift有一个基本的布尔(Boolean)类型,叫做Bool。布尔值指逻辑上的值,因为它们只能是真或者假。Swift提供两个布尔常量,true和false:

let orangesAreOrange = true
let turnipsAreDelicious = false

元组

元组(tuples)把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。

let http404Error = (404, "Not Found")
// http404Error is of type (Int, String), and equals (404, "Not Found")

元组的内容可以分解(decompose)成单独的常量和变量,然后你就可以正常使用它们了:

let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// Prints "The status code is 404"
print("The status message is \(statusMessage)")
// Prints "The status message is Not Found"

如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(_)标记:

let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"

你也可以通过下标来访问元组中的单个元素,下标从零开始:

print("The status code is \(http404Error.0)")
// Prints "The status code is 404"
print("The status message is \(http404Error.1)")
// Prints "The status message is Not Found"

你可以在定义元组的时候给单个元素命名:

let http200Status = (statusCode: 200, description: "OK")

这个元组的名字叫做http200Status,它的类型是(Int, String)。你可以通过名字来获取元素的值:

print("The status code is \(http200Status.statusCode)")
// Prints "The status code is 200"
print("The status message is \(http200Status.description)")
// Prints "The status message is OK"

可选类型

Swift的可选类型(optional types)表示:

可选类型有点像Objective-C中的nil指针,但是它们可以用于任何类型,不仅仅是类。可选类型表示的是值缺失,而不是值为nil。这样的设计可以让你避免在你的代码中使用nil值。

可选绑定

可选绑定(optional binding)用来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或变量。

if let constantName = someOptional {
    statements
}

隐式解析可选类型

有时候在变量的生命周期中,会确定一个可选类型变量总会有值。在这种情况下,每次都需要判断和解析可选值是非常麻烦的。这时候可以选择隐式解析可选类型(implicitly unwrapped optionals)。

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation point

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation point

错误处理

Swift提供了一种在运行时表示和抛出错误的机制。这个机制让你能够表示和抛出你自己的错误,并且把函数抛出的错误传递到程序的某个地方。

enum VendingMachineError: ErrorType {
    case InvalidSelection
    case InsufficientFunds(coinsNeeded: Int)
    case OutOfStock
}

throw VendingMachineError.InsufficientFunds(coinsNeeded: 5)

断言和先决条件

断言和先决条件用来检查在运行时一个必要的条件是否为真。如果条件判断的结果为true,代码继续运行。如果条件判断的结果为false,代码执行结束,你的应用被终止。

let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// This assertion fails because -3 is not >= 0.

if age > 10 {
    print("You can ride the roller-coaster or the ferris wheel.")
} else if age >= 0 {
    print("You can ride the ferris wheel.")
} else {
    assertionFailure("A person's age can't be less than zero.")
}
// Prints "You can ride the ferris wheel."