Switf入门到精通中
# 04.高级运算符和枚举
# 目录介绍
- 4.1 位与溢出运算符
- 4.1.1 位运算符应用
- 4.1.2 溢出运算符
- 4.2 运算符重载和自定义
- 4.2.1 重载运算符
- 4.2.2 自定义运算符
- 4.3 运算符的优先级
- 4.4 枚举创建和应用
- 4.4.1 枚举类型说明
- 4.4.2 枚举语法
- 4.4.3 枚举相关值
- 4.4.4 枚举原始值
- 5.1 结构体
- 5.1.1 什么是结构体
- 5.1.2 结构体语法
- 5.1.3 结构体案例
- 5.1.4 结构体应用场景
- 5.2 类
- 5.2.1 什么是类
- 5.2.2 类语法和定义
- 5.2.3 访问类属性
- 5.2.4 恒等运算符
- 6.1 属性
- 6.1.1 存储属性
- 6.1.2 延迟存储属性
- 6.1.3 计算属性
- 6.1.4 只读计算属性
- 6.1.5 属性观察器
- 6.1.6 全局变量和局部变量
- 6.1.7 类型属性
- 6.1.8 获取和设置类型属性的值
- 6.2 方法
- 6.2.1 实例方法
- 6.2.2 self属性
- 6.2.3 类型方法
- 6.3 构造
- 6.3.1 构造过程
- 6.3.2 构造器
- 6.3.3 默认属性值
- 6.3.4 构造参数
- 6.3.5 内部和外部参数名
- 6.3.6 可选属性类型
- 6.3.7 类的继承和构造过程
- 6.3.8 构造器的继承和重载
- 6.4 析构
- 6.4.1 析构过程
- 6.4.2 析构过程原理
- 6.4.3 析构语法
- 6.5 访问权限
- 6.5.1 访问权限分类
# 4.1 位与溢出运算符
# 4.1.1 位运算符应用
在计算机中,数据都是以二进制的形式存储的,位运算也是专门针对二进制数据的一种运算 方式。
在Swift 语言中,开发者在创建数值变量时可以通过追加“0b” 前缀的方式将数值设置为二 进制。
# 4.2 运算符重载和自定义
# 4.2.1 重载运算符
首先应该清楚重载的概念。重载的概念最初是针对函数的,对同 一个函数名,设置不同的参数类型以实现不同的功能被称为函数的重载。
# 4.2.2 自定义运算符
# 4.4 枚举创建和应用
# 4.4.1 枚举类型说明
枚举简单的说也是一种数据类型,只不过是这种数据类型只包含自定义的特定数据,它是一组有共同特性的数据的集合。
Swift 的枚举类似于 Objective C 和 C 的结构,枚举的功能为:
它声明在类中,可以通过实例化类来访问它的值。
枚举也可以定义构造函数(initializers)来提供一个初始成员值;可以在原始的实现基础上扩展它们的功能。
可以遵守协议(protocols)来提供标准的功能。
# 4.4.2 枚举语法
Swift 中使用 enum 关键词来创建枚举并且把它们的整个定义放在一对大括号内:
enum enumname {
// 枚举定义放在这里
}
2
3
定义以下表示星期的枚举:
// 定义枚举
enum DaysofaWeek {
case Sunday
case Monday
case TUESDAY
case WEDNESDAY
case THURSDAY
case FRIDAY
case Saturday
}
var weekDay = DaysofaWeek.THURSDAY
weekDay = .THURSDAY
switch weekDay {
case .Sunday:
print("星期天")
case .Monday:
print("星期一")
case .TUESDAY:
print("星期二")
case .WEDNESDAY:
print("星期三")
case .THURSDAY:
print("星期四")
case .FRIDAY:
print("星期五")
case .Saturday:
print("星期六")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 4.4.3 枚举相关值
相关值是当你在创建一个基于枚举成员的新常量或变量时才会被设置,并且每次当你这么做得时候,它的值可以是不同的。
定义一个名为 Student 的枚举类型,它可以是 Name 的一个字符串(String),或者是 Mark 的一个相关值(Int,Int,Int)。
enum Student{
case Name(String)
case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Runoob")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
print("学生的名字是: \(studName)。")
case .Mark(let Mark1, let Mark2, let Mark3):
print("学生的成绩是: \(Mark1),\(Mark2),\(Mark3)。")
}
2
3
4
5
6
7
8
9
10
11
12
# 4.4.4 枚举原始值
原始值可以是字符串,字符,或者任何整型值或浮点型值。每个原始值在它的枚举声明中必须是唯一的。
在原始值为整数的枚举时,不需要显式的为每一个成员赋值,Swift会自动为你赋值。
例如,当使用整数作为原始值时,隐式赋值的值依次递增1。如果第一个值没有被赋初值,将会被自动置为0。
enum Month: Int {
case January = 1, February, March, April, May, June, July, August, September, October, November, December
}
let yearMonth = Month.May.rawValue
print("数字月份为: \(yearMonth)。")
2
3
4
5
# 5.1 结构体
# 5.1.1 什么是结构体
Swift 结构体是构建代码所用的一种通用且灵活的构造体。
我们可以为结构体定义属性(常量、变量)和添加方法,从而扩展结构体的功能。
与 C 和 Objective C 不同的是:
- 结构体不需要包含实现文件和接口。
- 结构体允许我们创建一个单一文件,且系统会自动生成面向其它代码的外部接口。
结构体总是通过被复制的方式在代码中传递,因此它的值是不可修改的。
# 5.1.2 结构体语法
我们通过关键字 struct 来定义结构体:
struct nameStruct {
Definition 1
Definition 2
……
Definition N
}
2
3
4
5
6
# 5.1.3 结构体案例
下面是一个使用Swift中结构体的简单案例:
// 定义一个结构体
struct Person {
var name: String
var age: Int
// 结构体方法
func introduce() {
print("我叫\(name),今年\(age)岁。")
}
}
// 创建结构体实例
var person1 = Person(name: "Alice", age: 25)
var person2 = Person(name: "Bob", age: 30)
// 访问结构体属性
print(person1.name) // 输出: "Alice"
print(person2.age) // 输出: 30
// 调用结构体方法
person1.introduce() // 输出: "我叫Alice,今年25岁。"
person2.introduce() // 输出: "我叫Bob,今年30岁。"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
结构体是值类型,当我们将结构体赋值给另一个变量或常量时,会创建一个新的副本。这意味着person1和person2是独立的实例,它们的属性可以独立地进行修改。
# 5.1.4 结构体应用场景
与类相比,结构体是值类型,它们在传递和复制时会创建副本。这使得结构体在某些情况下更适合使用,特别是对于简单的数据类型和小型数据模型。
结构体在Swift中有许多应用场景,以下是一些常见的使用情况:
- 配置选项:结构体可以用于表示配置选项,例如游戏设置、应用程序配置或用户首选项。每个选项可以作为结构体的属性,以便轻松地进行设置和访问。
- 数据缓存:结构体可以用于创建轻量级的数据缓存,以便在应用程序中存储和传递数据。结构体的值类型特性使得复制和传递数据更加高效。
- API设计:结构体可以用于设计API,以提供一组相关的属性和方法。通过将相关功能封装在结构体中,可以提供更清晰、可读性更高的代码接口。
# 5.2 类
# 5.2.1 什么是类
Swift 类是构建代码所用的一种通用且灵活的构造体。
我们可以为类定义属性(常量、变量)和方法。
与其他编程语言所不同的是,Swift 并不要求你为自定义类去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类,系统会自动生成面向其它代码的外部接口。
# 5.2.2 类语法和定义
语法:
class classname {
Definition 1
Definition 2
……
Definition N
}
2
3
4
5
6
类定义:
class student{
var studname: String
var mark: Int
var mark2: Int
}
2
3
4
5
# 5.2.3 访问类属性
类的属性可以通过 . 来访问。格式为:实例化类名.属性名:
class studentMarks {
var mark1 = 300
var mark2 = 400
var mark3 = 900
}
let marks = studentMarks()
print("Mark1 is \(marks.mark1)")
print("Mark2 is \(marks.mark2)")
print("Mark3 is \(marks.mark3)")
2
3
4
5
6
7
8
9
# 5.2.4 恒等运算符
因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。
为了能够判定两个常量或者变量是否引用同一个类实例,Swift 内建了两个恒等运算符:
- 运算符为:=== 如果两个常量或者变量引用同一个类实例则返回 true
- 运算符为:!== 如果两个常量或者变量引用不同一个类实例则返回 true
class SampleClass: Equatable {
let myProperty: String
init(s: String) {
myProperty = s
}
}
func ==(lhs: SampleClass, rhs: SampleClass) -> Bool {
return lhs.myProperty == rhs.myProperty
}
let spClass1 = SampleClass(s: "Hello")
let spClass2 = SampleClass(s: "Hello")
if spClass1 === spClass2 {// false
print("引用相同的类实例 \(spClass1)")
}
if spClass1 !== spClass2 {// true
print("引用不相同的类实例 \(spClass2)")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6.3.1 构造过程
构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务。
Swift 构造函数使用 init() 方法。
与 Objective-C 中的构造器不同,Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。
类实例也可以通过定义析构器(deinitializer)在类实例释放之前执行清理内存的工作。
# 6.3.4 构造参数
你可以在定义构造器 init() 时提供构造参数,如下所示:
struct Rectangle {
var length: Double
var breadth: Double
var area: Double
init(fromLength length: Double, fromBreadth breadth: Double) {
self.length = length
self.breadth = breadth
area = length * breadth
}
init(fromLeng leng: Double, fromBread bread: Double) {
self.length = leng
self.breadth = bread
area = leng * bread
}
}
let ar = Rectangle(fromLength: 6, fromBreadth: 12)
print("面积为: \(ar.area)")
let are = Rectangle(fromLeng: 36, fromBread: 12)
print("面积为: \(are.area)")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 6.3.7 类的继承和构造过程
# 6.3.8 构造器的继承和重载
Swift 中的子类不会默认继承父类的构造器。
父类的构造器仅在确定和安全的情况下被继承。
当你重写一个父类指定构造器时,你需要写override修饰符。
class SuperClass {
var corners = 4
var description: String {
return "\(corners) 边"
}
}
let rectangle = SuperClass()
print("矩形: \(rectangle.description)")
class SubClass: SuperClass {
override init() { //重载构造器
super.init()
corners = 5
}
}
let subClass = SubClass()
print("五角型: \(subClass.description)")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 6.4 析构
# 6.4.1 析构过程
在一个类的实例被释放之前,析构函数被立即调用。用关键字deinit来标示析构函数,类似于初始化函数用init来标示。析构函数只适用于类类型。
# 6.4.2 析构过程原理
Swift 会自动释放不再需要的实例以释放资源。
Swift 通过自动引用计数(ARC)处理实例的内存管理。
通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。
例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前关闭该文件。
# 6.4.3 析构语法
var counter = 0; // 引用计数器
class BaseClass {
init() {
counter += 1;
}
deinit {
counter -= 1;
}
}
var show: BaseClass? = BaseClass()
print(counter)
show = nil
print(counter)
2
3
4
5
6
7
8
9
10
11
12
13
14
当 show = nil 语句执行后,计算器减去 1,show 占用的内存就会释放。
# 6.5 访问权限
# 6.5.1 访问权限分类
在 Swift 中,有以下几种访问权限修饰符(Access Modifiers)可用于控制类、结构体、属性、方法和其他成员的访问级别:
- open:最高访问级别,对于类和类的成员,可以被定义模块外的代码访问、继承和重写。
- public:对于类和类的成员,可以被定义模块外的代码访问,但不能被继承和重写。
- internal:默认的访问级别,对于类和类的成员,可以被同一模块内的代码访问,但不能被模块外的代码访问。
- fileprivate:对于类和类的成员,可以被同一源文件内的代码访问。
- private:对于类和类的成员,只能在定义它们的作用域内访问。
这些访问权限修饰符可以应用于类、结构体、枚举、属性、方法和初始化方法等。默认情况下,如果不显式指定访问权限修饰符,成员将具有 internal 访问级别。