「MacOS」Swift 第一章:基础部分

本来给swift单开了一个专栏,21年学的时候还是英文教程,现在22年都有中文教程啦,索性把之前的专栏都删了,新开一篇文章作为学习swift的个人笔记

参考链接

Swift官方中文教程页面

1 基础部分

下面是基础部分知识点概述

数据类型:

  • Int
  • Double
  • Float
  • Bool:true 和 false
  • String

集合类型

  • Array
  • Set
  • Dictionary
  • Tuple

变量类型
swift中的变量分为两类,变量与常量。变量在使用过程中可以对其进行修改;常量在使用过程中不会变化。两种类型的变量声明方式不同。

可选类型

  • Optional

1.1 变量与常量

常量的值一旦设定就不能改变,而变量的值可以随意更改。常量和变量必须在使用前声明,用let 来声明常量,用 var 来声明变量。两者的声明方式如下:

let a = 10  // 常量声明
var b = 0	// 变量声明
var x = 0.0, y = 0.0, z = 0.0	// 可以在一行中声明多个变量或常量,使用逗号隔开

1.2 变量与常量类型注解

对变量或常量的数值类型进行注释说明。注解格式如下:

var welcomeMessage: String // 为变量welcomeMessage注解,说明它是一个String类型变量
welcomeMessage = "Hello"

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

var red, green, blue: Double

如果在声明变量或常量时赋予了一个初始值,那么swift会对其类型执行“类型推断”,推断出这个常量或者变量的类型。

1.3 变量与常量命名规则

常量和变量名可以包含几乎所有的字符,包括 Unicode 字符:

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

一旦常量和变量声明为确定的类型,就不能使用相同的名字再次进行声明,或者改变其存储的值的类型,也不能将常量与变量进行互转,但可以更改现有的变量值为其他同类型的值

1.4 打印常量与变量

可以通过print(_:separator:terminator:)方法来打印变量或常量,它输出一个或多个值。其中,separator 和 terminator 参数具有默认值,因此正常使用时可以忽略。此外,该函数以换行符输出作为输出结尾,如果不想以换行符作为输出结尾,可以传递一个空字符给terminator:print(someValue, terminator:""

swift在输出中使用字符串插值,将变量插入字符串中输出:

var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
print("The current value of friendlyWelcome is \(friendlyWelcome)")
// 输出“The current value of friendlyWelcome is Bonjour!”

1.5 代码注释

  • 单行注释://
  • 多行注释:/* + */
    多行注释可嵌套使用

1.6 分号使用

当想要在同一行内写多条独立的语句时,可以使用分号隔开,就像python:

let cat = "🐱"; print(cat)
// 输出“🐱”

1.7 整数相关规则

  • 整数包括:带符号整数(正数、零、负数),无符号整数(正数、零)
  • Swift 提供8、16、32和64位的有符号和无符号整数类型
  • 可以访问不同整数类型的 min 和 max 属性来获取对应类型的最小值和最大值:
    let minValue = UInt8.min  // minValue 为 0,是 UInt8 类型
    let maxValue = UInt8.max  // maxValue 为 255,是 UInt8 类型
    
  • Int、Uint在不同平台上占有位数不同
  • 一般情况不建议使用Uint,统一使用 Int 可以提高代码的可复用性;使用Uint一般是在优化性能、内存占用等场景使用

1.8 浮点数相关规则

  • Double表示64位浮点数,到小数点后15位
  • Float表示32位浮点数,到小数点后6位

1.9 类型安全和类型推断

swift是类型安全的语言,跟C++类似,但不同的地方在于,swift会在第一次接收数据时,执行数据类型判断,确定该变量的数据类型。当推断浮点数时,swift默认选择Double数据类型。

1.10 数值型字面量

整数字面量规则:

  • 一个十进制数,没有前缀
  • 一个二进制数,前缀是 0b
  • 一个八进制数,前缀是 0o
  • 一个十六进制数,前缀是 0x

浮点数字面量规则:

  • 一个十进制,没有前缀
  • 一个十六进制,前缀是 0x

具体举例有点复杂,看看就行

1.11 数据类型转换

如果数字超出了常量或者变量可存储的范围,编译的时候会报错。由于每种整数类型都可以存储不同范围的值,所以必须根据不同情况选择性使用数值型类型转换。

整数转换可以将低位数据升位后与高位数据计算:

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
// pi 等于 3.14159,所以被推测为 Double 类型

1.12 类型别名

类型别名就是给现有类型定义另一个名字,可以使用typealias关键字来定义类型别名。例如,当要给现有类型取一个更有意义的名称时,可以:

typealias AudioSample = UInt16 // AudioSample与UInt16关键字等价
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound 现在是 0

1.13 布尔值

如果在需要使用布尔值的地方,使用了非不二之,机制会报错。例如:

let i = 1
if i {
    // 这个例子不会通过编译,会报错
}

let i = 1
if i == 1 {
    // 这个例子会编译成功
}

1.14 元组

元组可以包含所有类型和所有元素长度。

  • 元组的声明和解构如下:

    let http404Error = (404, "Not Found")
    // http404Error 的类型是 (Int, String),值是 (404, "Not Found")
    let (statusCode, statusMessage) = http404Error
    print("The status code is \(statusCode)")
    // 输出“The status code is 404”
    
  • 支持python中下划线_的用法

    let (justTheStatusCode, _) = http404Error
    
  • 可以通过下标来访问元组中的单个元素,下标从零开始

    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”
    
  • 可以在定义元组的时候给单个元素命名,然后通过名字来获取这些元素的值

    let http200Status = (statusCode: 200, description: "OK")
    print("The status code is \(http200Status.statusCode)")
    // 输出“The status code is 200”
    print("The status message is \(http200Status.description)")
    // 输出“The status message is OK”
    

1.15 可选类型

可选类型的出现主要是为了解决传入值缺失的情形,可选类型表示两种情况:值存在或值缺失。例如,将字符串String "123"转换成 Int 整数类型,这是能够成功的,而我们却不能将"Hello"转换成Int 整数类型。那么当接收的字符串内容未知时,可选类型就派上用场了:

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int"

可选类型的声明,在数据类型后面需要加上一个?,例如 Int 可选类型应该写作Int?,问号暗示包含的值是可选类型,说明该变量只能包含一个 Int 类型的值或者不包含任何类型值。

nil

swift中的 nil 是一个确定的值,用来表示值缺失。可以将 nil 赋值给变量或常量,表示没有值:

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

此外,nil 只能用于可选常量或变量。如果声明了一个可选常量或变量没有赋值,那么它们会被自动赋值nil:

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

if 语句和 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 和 wihle 语句中,也可以用于常量或变量。下面的例子中使用常量(let)举例:

if let actualNumber = Int(possibleNumber) {
    print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
    print("\'\(possibleNumber)\' has no value and could not be converted to an integer")
}
// 其中可选类型为possibleNumber,如果possibleNumber中包含值,则将它赋值给actualNumber,并进入第一个print;如果possibleNumber中没有值,则进入第二个print

如果在访问它包含的值后不需要引用原来的可选常量或是可选变量,可以对新的常量或是新的变量使用相同的名称:

let myNumber = Int(possibleNumber)
// 此处 myNumber 为一可选整型
if let myNumber = myNumber {
	// 此处 myNumber 为一不可选整型
	print("My number is \(myNumber)")
}
// 输出 "My number is 123"

对于上面的 if 部分,还可以有更简洁的写法:

let myNumber = Int(possibleNumber)
// 此处 myNumber 为一可选整型
if let myNumber{
	print("My number is \(myNumber)")
}
// 输出 "My number is 123"

可以在一个 if 中使用多个可选绑定,用逗号隔开,如果多个可选绑定中有一个为 false,则整个 if 被判定为 false。下面两个 if 的表达是等价的:

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”

隐式解析的可选类型

当一个常量或变量为可选类型时,每次使用其中包含的值时都需要进行解析,而在有的情况,当一个常量或变量第一次被赋值时,就可以确定之后每次使用都是含值的。为了避免后续无必要的解析,swift提供了隐式解析方法。

声明隐式解析只需要将可选类型后面的?修改为!即可:

let possibleString: String? = "An optional string." // 声明一个可选类型
let forcedString: String = possibleString! // 需要感叹号来获取值

let assumedString: String! = "An implicitly unwrapped optional string." // 声明一个隐士解析可选类型
let implicitString: String = assumedString  // 不需要感叹号即可获取值,因为上一句已经确定assumedString中含值
let optionalString = assumedString // 当optionalString没有指明变量类型时,会自动被赋值为assumedString的变量类型,此时assumedString是一个可选类型
// optionalString 的类型是 "String?",assumedString 也没有被强制解析。

如果一个隐式解析可选类型中不包含值,但却被尝试取值,会触发运行错误。为了避免出现该错误,我们可以对隐式解析可选类型执行可选类型是否含值一样的判断、解析:

if assumedString != nil {
    print(assumedString!)
}
// 输出“An implicitly unwrapped optional string.”
if let definiteString = assumedString {
    print(definiteString)
}
// 输出“An implicitly unwrapped optional string.”

注意,如果一个变量之后可能变成 nil 的话就不要使用隐式解析可选类型,使用普通的可选类型即可。

1.16 错误处理

错误处理主要用于应对程序中可能会遇到的错误条件。错误处理需要程序在两个地方进行定义:

// 在函数定义后面加上 throw 关键字
func canThrowAnError() throws {
    // 这个函数有可能抛出错误
}

// 在函数调用处加上 do 和 try 关键字,使用 catch 关键字来应对错误发生时的应对操作
do {
    try canThrowAnError()
    // 没有错误消息抛出
} catch {
    // 有一个错误消息抛出
}

一个上面定义的实际例子:

func makeASandwich() throws {
    // 函数功能
}

do {
    try makeASandwich() // 预判makeASandwich()中可能发生的错误
    eatASandwich()
} catch SandwichError.outOfCleanDishes { // 当发生SandwichError.outOfCleanDishes错误时,应对处理为washDishes()
    washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
	// 当发生SandwichError.missingIngredients错误时,应对处理为buyGroceries()
    buyGroceries(ingredients)
}

其他细节会有专门的“错误处理”章节介绍。

1.17 断言和先决条件

断言和先决条件是对一个程序执行过程中执行状态的检查,如果执行状态满足,则继续往下执行程序,如果不满足则终止程序执行。

断言能够帮助在开发阶段找到错误和不正确的假设,先决条件能够帮助在生产环境中探测到存在的问题。断言和先决条件并不是用来处理可以恢复的或者可预期的错误,可以强制检查数据和程序状态,使得程序可预测的中止。

使用断言进行调试

可以调用 Swift 标准库的assert(_:_:file:line:) 函数来写一个断言,向函数传入一个结果为布尔值的表达式以及一条信息,那么当表达式为 false 时,该条信息会被显示:

let age = -3
assert(age >= 0, "A person's age cannot be less than zero") // 显示信息的写法
assert(age >= 0) // 不显示信息的写法
// 因为 age < 0,所以断言会触发,当断言触发,程序后续内容不会被执行,程序终止;如果断言没被触发,则程序忽略断言部分,继续向后执行

如果代码已经检查了条件,可以使用 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.")
} // 用于显示程序执行过程中的断言记录

强制执行先决条件

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

可以使用全局 precondition(_:_:file:line:) 函数来写一个先决条件,向函数传入一个结果为布尔值的表达式以及一条信息,那么当表达式为 false 时,该条信息会被显示:

// 判断下标是否合法
precondition(index > 0, "Index must be greater than zero.")

可以调用preconditionFailure(_:file:line:)方法来表明出现了一个错误。例如,switch 进入了 default 分支,但是所有的有效值应该被任意一个其他分支(非 default 分支)处理。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值