Swift笔记 - 基础部分

基础部分

swift 包含了 C 以及 Objective-C 上所有的基础数据类型。

Int 整型值
DoubleFloat 浮点型
Bool 布尔型值
String 文本类型数据
Array 数组
Set 集合
Dictionary 字典

swift增加了Objective-C中没有的高阶数据类型:元组(Tuple)。元组可以让你创建或者传递一组数据。

Swift 增加了 可选(Optional)类型,用于处理值缺失的情况。

Swift 是一门类型安全的语言。

变量和常量

常量和变量必须在使用前声明,let:常量 var:变量

let maxNumber = 10
var currentTemp = 0

你可以再一行中声明多个常量或多个变量,用逗号隔开

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

注意

如果你的代码中有不需要改变的值,请使用 let 关键字将他声明为常量。

类型注解

声明常量或者变量的时候,可以加上类型注释(type annotation), 说明常量或者变量中要存储的值的类型。

var welcomeMessage: String  

你可以在一行中定义多个同样类型的变量,用逗号分割,并在最后一个变量名之后添加类型注解:

var red, green, blue: Double

注意

一般来说你很少需要写类型注解。

如果你在声明常量或者变量的时候赋了初始值,Swift可以推断出这个常量或者变量的类型。

常量和变量的命名

常量和变量名激活包括所有的字符,包括Unicode字符:

let π = 3.14159
let 你好 = "你好世界"
let  = "dogcow"

常量和变量名不能包含数学符号,箭头,不能以数字开头。

输出常量和变量

可以用print(_:separator:terminator:)函数来输出当前常量或变量的值:

let a = "Candy"
print(candy)
// 输出 “Candy”

插值

let day = "Sunday"
print("The day is \(day)")
注释
// 这是当行注释
/** 
 * 这是多行注释
*/
分号

Swift 并不强制要求你在每条语句的结尾使用分号(

let cat = ""; print(cat)
整数
整数范围

Swift 提供了 8、16、32和64位的 有符号 和 无符号证书类型。命名方式和C语音很像。

let minValue = UInt8.min    // minValue为0
let maxValue = UInt8.max    // maxValue为255
Int

一般情况下,不需要指定整数的长度。默认情况下

  • 在32位平台上:IntInt32 长度相等

  • 在64位平台上:IntInt64 长度相等

即使是在32位平台上,Int 可以存储的整数范围也可以达到 -2,147,483,648 ~ 2,147,483,647

UInt

Swift 也提供了一个特殊的无符号类型 UInt,长度与当前平台的原生字长相同:

  • 在32位平台上,UIntUInt32 长度相同。
  • 在64位平台上,UIntUInt64 长度相同。

注意

尽量不要使用UInt,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。

除了这种情况,最好使用Int 。

即使需要存储的值是 非负的。

统一使用 Int可以提高代码的复用性,避免不同类型数字之间的转换。

浮点数

浮点类型比整数类型表示的范围更大,可以存储比 Int 类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:

  • Double 表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。
  • Float 表示32位浮点数。精度要求不高的话可以使用此类型。

注意

Double 精确度很高,至少有 15 位小数,而 Float 只有 6 位小数。选择哪个类型取决于你的代码需要处理的值的范围,在两种类型都匹配的情况下,将优先选择 Double

类型安全和类型判断

Swift 是一个类型安全(type safe)的语言. 它会在编译代码的时候进行类型检查 (type checks), 把不匹配的类型标记为错误,可以让你在开发过程中发现并修复错误。

当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说 每次声明 常量、变量的时候都需要指定类型。如果你没有显示指定类型,Swift会使用类型判断(type inference)来选择合适的类型。

例如:

let a = 42
// a 会被推测为 Int

let b = 3.14
// b 会被推测为 Double

let c = 3 + 0.14
// c 会被推测为 Double
数值型字面量

整数字面量可以写作:

  • 十进制:没有前缀
  • 二进制:前缀 0b
  • 八进制: 前缀 0o
  • 十六进制:前缀 0x

例如:

let a = 17
let b = 0b1001
let c = 0o21
let d = 0x11

数值类字面量可以通过额外的格式来增强可读性。 整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量:

let a = 000123.456
let b = 1_000_000
let c = 1_000_000.000_000_1
数值型类型转换

通常来讲,即使代码中的整数常量和变量已知非负,也请使用 Int 类型。

总是使用默认的整数类型可以保证 整数常量和变量 可以直接使用并复用

并且可以匹配 整数类字面量 的 类型推断。

整数转换

不通整数类型的变量和常量可以存储不通的数字。

Int8类型的常量或者变量可以存储的数字范围:-128 ~ 127

UInt类型的常量或者变量能存储的数字范围:0 ~ 255

let cannotBeNagetive: UInt8 = -1
// UInt8 类型不能存储负数,所以会报错

let tooBig : Int8 = Int8.Max + 1
// Int8 类型不能存储超过最大数,所以会报错

由于每种整数类型都可以存储不通范围的值,所以你必须根据不同情况,选择性使用 数值型 类型转换。

这种选择性使用的方式,可以预防隐士转换的错误,并且让你的代码中的类型转换意图变得清晰。

/**
 * 因为类型不同,不能直接相加
 * 调用Int16(one) 来创建一个新的 UInt16 数字,才能相加
*/
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt(one)

整数和浮点数转换

let three = 3
let pointOneFourOneFiveNice = 0.14159
let pi = Double(three) + pointOneFourOneFiveNice
// pi 等于3.14159 所以被推测为 Double 类型

let integerPi = Int(pi)
// integerPi 等于 3 , 所以被推测为 Int 类型

注意:

当用这种方式来初始化一个新的浮点数值,浮点会被阶段。

也就是说 4.71 会变成 4 , -3.9 会变成-3

类型别名

类型别名 (type aliases) 就是给现有类型定义另一个名字。例如:

typealias AudioSample = UInt16  

var maxAmplitudeFound = AudioSample.min
布尔值

Swift 有一个基本的布尔(Boolean)类型, 加做 Bool

Swift 有两个布尔常量,truefalse

let orangesAreOrange = true
let turnipsAreDelicious = false

// 条件语句
if turnipsAreDelicious {
    print("Mmm, tasyty turnips!")
} else {
    print("Eww, turnips are horrible")
}
元组

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

例如:

let httpError = (404, "Not Found")

let (statusCode, statusMessage) = httpError
print("The status code is \(statusCode)")
//输出“The status code is 404”

print("The status message is \(statusMessage)")
// 输出“The status message is Not Found”

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

let (statusCode, _) = httpError
print("The status code is \(justTheStatusCode)")

可以通过下标访问元组:

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”
可选类型

使用可选类型(optionals) 来处理可能缺失的情况。可选表示两种可能:

  1. 可能有值:通过解析来访问可选值
  2. 没有值

注意:

CObjective-C 中并没有 可选类型 这个概念。

最接近的是Objective-C中的一个特性,方法返回值:对象 or nil, nil表示"缺少一个合法的对象"。

Swift的可选类型可以让你暗示任意类型的缺失。

例如:

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)

// convertedNumber 被推测为类型“Int?” , 或者类型为"Optional Int"

因为该构造器可能会失败,所以返回一个可选类型(optional)Int, 而不是一个Int.

一个可选的Int 被写成Int? 。问号表示暗示包含的值是可选类型的。也就是说可能包含Int也可能不包含值。

nil

你可以给可选变量赋值为nil,表示它没有值:

var a: Int? = 404
// a 包含一个可选的 Int 值 404
a = nil
// a 现在不包含值

注意:

nil不能用于非可选的常量和变量。

如果代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。

如果声明一个可选常量或者变量,但是没有赋值,它们会自动被设置成nil:

var temp: String?
// temp 被自动设置为nil

注意:

Swift 的 nil 和 Objective-C 中的 nil 并不一样。

OC:nil是一个指向不存在对象的指针。

Swift:nil不是指针。它是一个确定的值,用来表示值缺失。

任何类型的可选状态都可以被设置为nil,不只是对象类型。

if语句以及强制解析

你可以使用if 语句 和 nil比较来判断一个可选值是否包含值。

如果有可选类型有值,它将不等于nil

if temp != nil {
    print('temp contain some value')
}

当你确定可选类型确实包含值之后,你可以在可选的名字后面加感叹号(!)来获取值。

这个感叹号表示“我知道这个可选有值,请使用它”。这个称为可选值的强制解析(forced unwarpping)

var temp: String?
if temp != nil {
    print("temp value is \(temp!)")
}
// 输出 temp value is 123

注意:

使用 来获取一个不存在的可选值,会导致运行错误。 使用!来强制解析之前,一定要确定可选包含一个非nil的值。

可选绑定

使用可选绑定(optional binding) 来判断可选类型是否包含值, 如果包含 就把值 赋给一个临时常量 或者 变量。

可选绑定 可以用在 ifwhile语句中, 这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值 赋给 一个常量或者变量。

例如:

if let constantName = someOptional {
    statements
}

如果Int(number)返回的可选Int包含一个值,创建一个 temp的新常量并且将可选包含的值给它

if let temp = Int(number) {
    print("\(number) has an integer value of \(temp)")
}   else {
    print("\(number) could not be converd to an integer")
}

你可以包含多个可选绑定 或者 布尔条件在一个if 语句中,只需要用逗号分开就行。

只要有任意一个可选绑定的值为nil, 或者任意 bool 条件为 false,则整个if条件判断为false

例如:

if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNmuber < secondNumber {
    print("\(firstNumber) < \(secondNumber)")
}

注意

if条件语句中使用常量和变量来创建一个可选绑定,仅在if语句的句中(body)才能获取到值。

相反,在guard语句中使用常量和变量来创建一个可选绑定,仅在guard语句外且语句后才能获取到值。

隐式解析可选类型

可选类型暗示了 变量或常量 可以没有值。 可选 可以通过 if语句来判断是否有值,如果有值的话,可以通过可选绑定来解析值。

有时候,第一次被赋值之后,可以确定一个可选类型总是有值。在这种情况下,每次判断和解析可选值 是 非常低效的,因为可以确定它总会有值。

这种类型的可选状态可以呗定义为:隐式解析可选类型(implicitly unwrapped optionals)

把想要用作可选类型后面的问号(String?)改成感叹号(String!) 来声明一个隐式解析可选类型,可以再定义它时,直接把感叹号放在可选类型的后面。

let possiableString: String? = "An optional String."
let forceString: String = possableString!  // 需要感叹号来获取值

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感叹号

你可以把隐式解析可选类型当做一个可以自动解析的可选类型。

当你使用一个隐式解析可选值时,Swift 首先把她当做普通的可选值;

如果它不能被当成可选类型使用,swift会强制解析可选值。

在以上的代码中,可选值`

let possiableString: String? = "An optional String."
let forceString: String = possableString!  // 需要感叹号来获取值

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感叹号

你可以把隐式解析可选类型当做一个可以自动解析的可选类型。

当你使用一个隐式解析可选值时,Swift 首先把她当做普通的可选值;

如果它不能被当成可选类型使用,swift会强制解析可选值。

在以上的代码中,可选值`

let possiableString: String? = "An optional String."
let forceString: String = possableString!  // 需要感叹号来获取值

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感叹号

你可以把隐式解析可选类型当做一个可以自动解析的可选类型。

当你使用一个隐式解析可选值时,Swift 首先把她当做普通的可选值;

如果它不能被当成可选类型使用,swift会强制解析可选值。

在以上的代码中,可选值`

let possiableString: String? = "An optional String."
let forceString: String = possableString!  // 需要感叹号来获取值

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感叹号

你可以把隐式解析可选类型当做一个可以自动解析的可选类型。

当你使用一个隐式解析可选值时,Swift 首先把她当做普通的可选值;

如果它不能被当成可选类型使用,swift会强制解析可选值。

在以上的代码中,可选值assumedString在把自己的值给implicitString之前会被强制解析,原因是

implicitString本身的类型是非可选类型的String

下面的代码中,optionalString 并没有显示的数据类型。那么根据类型判断,它是一个普通的可选类型。

let optionString = assumedString
// optionalString 的类型是 "String?",assumedString 也没有被强制解析。
错误处理

可以使用 错误处理(error handling) 来处理执行中可能遇到的错误条件

当一个函数遇到错误条件,它能报错。调用函数的地方能抛出错误消息并合并处理

func canThrowAnError() throws{
    
}

一个函数可以通过在声明中添加 throws 关键词来抛出错误消息。

当抛出错误消息时,你应该在表达式中前置 try 关键词

do{
    try canThrowAnError()
    // 没有错误消息抛出
} catch {
    // 哟一个错误消息抛出
}

一个do语句创建了一个新的包含作用域, 使得错误能被传播到一个或者多个catch 从句

例如:

func makeASandWich() throws {
    // ...
}

do {
    try makeASandWich()
    eatASandWich()
} catch SandwichError.outOfCleanDishes{
    
} catch SandwichError.missingIngredients(let ingredients){
    buyGroceries(ingredients)
}
断言和先决条件

断言和先决条件是在运行时所做的检查。你可以使用他们来检查执行后续代码之前,是否一个必要的条件已经满足了。如果断言或者先决条件中的布尔条件评估结果为true,则代码会继续执行,如果是false,当前状态无效,代码执行结束。

断言帮助你在开发阶段找到错误和不正确的假设,先决条件帮助你在生产环境中探测到存在的问题。

断言和先决条件的不同点是,他们什么时候进行状态检测:断言仅在调试环境运行,而先决条件则在调试环境和生产环境中运行。在生产环境中,断言的条件将不会进行评估。这个意味着你可以使用很多断言在你的开发阶段,但是这些断言在生产环境中不会产生任何影响。

使用断言进行调试
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// 因为age = -3 , 所以断言能触发
强制执行先决条件

当一个条件可能为假,但是继续执行代码要求必须为真的时候,可以使用先决条件。

你可以使用全局preconditon(_:_:file:line:) 函数来写一个先决条件。向这个函数传入一个结果为true 或者false 的表达式 以及 一条信息,当表达式的结果为 false的时候这条信息会被显示:

// 例如使用先决条件来检查是否下标越界,或者来检查是否将一个正确的参数传给函数。
precondition(index > 0, "Index Must be greater than zero.")
// 在一个下标里的实现

注意

如果你使用 unchecked 模式(-Ounchecked)编译代码,先决条件将不会进行检查。编译器假设所有的先决条件总是为 true(真),他将优化你的代码。然而,fatalError(_:file:line:) 函数总是中断执行,无论你怎么进行优化设定。

你能使用 fatalError(_:file:line:) 函数在设计原型和早期开发阶段,这个阶段只有方法的声明,但是没有具体实现,你可以在方法体中写上 fatalError("Unimplemented")作为具体实现。因为 fatalError 不会像断言和先决条件那样被优化掉,所以你可以确保当代码执行到一个没有被实现的方法时,程序会被中断。

你可能感兴趣的:(Swift笔记 - 基础部分)