常量与变量
常量是赋值之后就不需要更改的,也不允许更改。变量是以后可以随便更改的。
如何声明
/* 会根据赋予的初值自动判断数据类型 */
let maximumNumberOfLoginAttempts = 10 // 常量声明
var currentLoginAttempt = 0 // 变量声明
var x = 0.0, y = 0.0, z = 0.0 // 一次性赋多个值的方法
类型标注
有初始值的时候就不用标明类型,若没有初试值的时候就需要标明类型
var welcomeMessage: String // 记住是紧接着一个冒号再接一个空格
var red, green, blue: Double // 一次性声明多个变量
常量与变量的命名规则
- 名字里不能包含的字符有
- 空白字符
- 数学符号
- 箭头
- private-use Unicode scalar values(私有Unicode标量值)
- line- and box-drawing characters.
- 名字不能以数字开头,但其它地方可以有数字。
- 无论是常量还是变量,一旦规定了类型,以后就不能再更改。
- 如果你要使用Swift关键字命名,需要用反引号`包裹,但不建议使用关键字。
打印常量与变量
使用的函数是print(_:separator:terminator:),其中的参数separator和terminator有默认值,不需要的话可以忽略它们,它们的详细用法以后再补。
var friendlyWelcome = "Bonjour!"
print(friendlyWelcome) // Bonjour会显示在console上
print("The current value of friendlyWelcome is \(friendlyWelcome)") // 常量或变量插入字符串显示的方法。
注释
- 单行注释
// single line comment。 - 多行注释
/* multiline comments */,多行注释是可以嵌套使用的(与C不一样的地方)。
分号的用法
Swift是不需要分号;来表示结束的。
但如果你需要将多行语句写到一行上面,那么就需要分号;来表示分割。
let cat = "🐱"; print(cat)
整数
整型数的命名规律:
UInt8:表示8为无符号整型数。Int32:表示32为有符号整型数。
整数范围
使用min和max属性来获取最小值和最大值,记住使用属性(properties)是不需要加圆括号的。
let minValue = UInt8.min // minValue = 0
let maxValue = UInt8.max // maxValue = 255
Int和UInt
它们的范围会根据你的机器硬件而调整。
浮点数
float有6位小数点精度。Double有15位小数点精度。- 若无特别情况,推荐使用
Double
类型安全和类型推断
- 简单来说,
Swift是类型安全的语言,它会自动检测出类型不匹配的错误(与C不一样,在没有你明确说明的情况下,不会自动发生强制类型转换,Int转换成Double也会被认为是error)。 Swift也可以根据初始值自动判定类型,不用你明确说明。- 浮点数会被判定成
Double
数字字面值
- 不同前缀表示不同的进制
- 十进制:无前缀
- 二进制:
0b - 八进制:
0o - 十六进制:
0x
- 科学计算法
- 十进制的指数用
e(大小写都可以),表示,
1.25e-2 = 0.0125 - 十六进制的浮点数的指数用
p(大小写都可以),表示,
0xFp2 =60.0
let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0 // 上面都是十进制值12.1875的表示法 - 十进制的指数用
- 方便阅读
- 包含多余的
0 - 包含下划线
_
let paddedDouble = 000123.456 let oneMillion = 1_000_000 let justOverOneMillion = 1_000_000.000_000_1 // 上面的写法都是合法的 - 包含多余的
数字类型转换
如上面所说的,类型的转换必须明确说明,否则会产生错误。
// 下面的语句是错误的
let cannotBeNegative: UInt8 = -1
let tooBig: Int8 = Int8.max + 1
// 两个不同类型的整数相加,必须明确说明转换。
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
类型别名
使用关键字typealias可以给类型起别名
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0
布尔值
true和false
另外,1不能代表true和0不能代表false,这也说明了类型安全。
// 下面语句是错误的
let i = 1
if i {
code
}
// 下面是正确的
let i = 1
if i == 1 {
code
}
Tuples
Tuples可以将多个(不限于2个)不同类型的值组合在一起。作为函数返回值很有用。
下面是它的一些用法
let http404Error = (404, "Not Found")
// 直接通过名字索引
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")
// 可以忽视你不想要的元素
let(justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// 也可以通过下标索引
print("The status code is \(http404Error.0)")
print("The status message is \(http404Error.1)")
// 或者直接给元素命名
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
print("The status message is \(http200Status.description)")
Optionals
先看一个例子,Swift可以将String直接转换成Int的,如"123"可以成功转换,但"Hello"是不可以转换成数字的。
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
/* convertedNumber的类型不是Int,而是Int?,也就是optional Int。
因为它有可能转换不成功,除了数字可以转换成功,其它的类型都被转换成nil
所以这时候的optionals就很有用
*/
nil可以使用在任何类型上面,但必须是声明成optionals的类型。
nil的意思是不代表任何值,但它不是空指针。
var surveyAnswer: String?
// 若没有赋初值,Swift会自动将它设置成nil,而不是空字符串
使用!解包optionals去使用该值
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
总之,nil和!都只能使用在被声明成optional类型的值上使用,而且解包一个值必须先确定它不是nil。
Optional Binding
你在《iOS Apprentice》经常见到的。
/* 下面的let也可以是var */
if let constantName = someOptional { // 如果someOptional不是nil就进行赋值,选择性解包。
statements
}
// 下面的逗号就相当于&,全部条件成立,if里面的语句才会被执行。
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
Implicitly Unwrapped Optionals
还有一种东西叫模糊解包,主要是用在class initialization的过程中。就是说它保证是有初始值的,所以以后在获取它的值的时候就不需要加叹号!了。你直接看代码感受一下。
/* normal optionals */
let possibleString: String? = "An optional string."
let forcedString: Sting = possibleString! // 需要叹号解包
/* Implicitly Unwrapped Optionals */
let assumedString: String! = "An implicitly unwrapped optional string." // 注意声明类型的时候有叹号!
let implicitsString: String = assumedString // 不需要叹号解包,直接使用即可
注意:
- 若一个
Implicitly Unwrapped Optionals是nil的时候,你去获取它,就会产生一个运行时错误(runtime error)。 - 你也可以把
Implicitly Unwrapped Optionals当作正常的optionals使用。/* 可以判断是否是nil,也可以使用叹号解包 */ if assumedString != nil { print(assumedString!) } /* 也可以进行optionals binding */ if let definiteString = assumedString { print(definiteString) }
Error Handling
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceroes(ingredients)
}
在do里面try调用了一个可以抛出error的函数makeASandwich(),如果makeASandwich()没有错误则执行eatASandwich(),如果抛出了一个错误,catch根据不同的错误会执行不同的error处理函数。
Assertions and Preconditions
断言和先决条件,与error handling不同的是,不满足断言和先决条件的时候,程序是会直接终止运行的,也就是说程序没有改正错误的机会。
断言和先决条件不同的地方是,断言只在debug阶段其作用,先决条件在debug和production都起作用。
所以你可以在开发阶段尽情的使用断言来辅助你方便地调试程序。
Debugging with Assertions
使用Swift标准库函数assert(_:_:file:line)来使用断言。执行前两条代码:
let age = -3
assert(age >= 0, "A person's age can't be less than zero.") // 如果给到函数的条件是false,则终止进程并打印信息
/* 也可以不要说明信息*/
assert(age >= 0)
会终止进程并产生如下错误。
下面是不需要检查condition的用法,使用函数assertionFailure(_:file:line:)
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.")
}
Enforcing Preconditions
在先决条件中,与Assertions的两个函数对应的是precondition(_:_:file:line:)和preconditionFailure(_:file:line:)
因为编译器存在
uncheck mode的这样一个模式,开启了这个模式之后,先决条件会失效,即precondition()永远被判定为true。所以存在一个叫fatalError(_:file:line:)的函数,不管是什么编译模式,它都能起作用去终止进程。