1. Struct
Swift中的常见类型Bool,Int,Double,Array,String,Dictionary等都是结构体,类和枚举占比较少;
结构体经过编译会自动生成的一个或者多个可传入成员值的构造方法,以保证所有的成员变量都有初始值;
结构体中的成员可以有默认值。
struct Point {
var x: Int
var y: Int = 0
}
var p1 = Point(x: 10, y: 10)
var p2 = Point(x: 10) // 由于y有默认值,所以初始化的时候可以不用初始化y.
1.1 自定义初始化器
当有了自定义的初始化器,编译器就不会再自动生成其它的初始化器。
struct Point {
var x: Int
var y: Int = 0
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
// 那么下面这样初始化 就会报错
var p = Point(x: 10)
// 只能通过自定义的初始化器来初始化
var p = Point(x: 10, y: 10)
1.2 结构体的内存结构
struct Point {
var x: Int = 0
var y: Int = 0
var origin: Bool = false
}
print(MemoryLayout<Point>.size) // 输出17 个字节,表示这个结构体用了17个字节,每个Int类型占8个字节
print(MemoryLayout<Point>.stride) // 输出24 个字节,表示这个结构体被分配了24个字节
print(MemoryLayout<Point>.alignment) // 输出8个 字节,对齐参数: 8个字节
2. Class
与结构体有区别的是,编译器不会为类自动生成可传入成员值的构造方法;
类中的成员都有初始值,则编译器会自动生成无参的初始化器;
注:成员的初始化实际上在这个无参初始化器中完成的。
/***类不会自动生成可传入成员值的初始化器***/
class Point {
var x: Int = 0
var y: Int = 0
}
// 那么下面这样初始化 就会报错,因为Class不会自动生成可传入值的初始化器。
var p = Point(x: 10)
// 而只会生成无参的初始化器,下面的会正常调用
var p = Point()
/***成员没有初始化,无参的初始化器也不会调用成功****/
class Point {
var x: Int
var y: Int
}
// 由于成员没有初始化,则下面无参数的初始化器会报错
var p = Point()
3. Swift中Struct和Class的区别
struct无法继承,class可继承;
struct是值类型,体积轻量,存放于栈区;
class是引用类型(指针类型),内容存放于堆区,只在栈内存汇总存放类实例的内存地址。
class Size {
var width = 1
var height = 2
}
struct Point {
var x = 3
var y = 4
}
func test() {
var size = Size()
var point = Point()
}
上述代码内存结构如下,Int和指针地址均分别占8个字节:
3.1 值类型
值类型赋值给var、let或者给函数传参,是直接将所有的内容拷贝一份。
产生了全新的内容空间,相当于深拷贝(deep copy)
struct Point {
var x: Int
var y: Int
}
func test() {
var p1 = Point(x: 10,y: 20)
var p2 = p1 //由于是深拷贝,这时候p2和p1有各自的内存空间
}
// 内存分布如下图
p2.x = 11
p2.y = 22
// 而此时 p1.x = 10, p1.y = 20, 未变,因为他们有相对独立的内存空间
注意:在Swift标准库中,为了提升性能,String,Array,Dictionary,Set采用了Copy On Write,当有“写”操作的时候,才会真正的执行拷贝操作。
3.2 引用类型
引用类型的var, let或者给函数传参,是将内存地址拷贝一份,而这个内存地址指向同一个文件,相当于浅拷贝(shallow copy)。
class Size {
var width: Int
var height: Int
init(width: Int, height: Int) {
self.width = width
self.height = height
}
}
func test() {
var s1 = Size(width: 10, height: 20)
var s2 = s1 // s1的内存地址赋给了s2
}
s2.width = 11
s2.height = 22
// 此时s1.width = 11,s1.height = 22,因为s1和s2同用一块堆内存空间。
3.3 值类型和引用类型的let
// 总结:let类型的值类型不可以改变, 而let类型的的引用类型里面的成员可以改
struct Point {
var x: Int
var y: Int
}
class Size {
var width: Int
var height: Int
init(width: Int, height: Int) {
self.width = width
self.height = height
}
}
// 定义一个Point常量
let p = Point(x: 10, y: 20) // p的内存不可以改,即p占的16个字节的栈内存不可以变
// 给这个常量赋值
p = Point(x: 11,y: 22) // 这句代码直接报错
p.x = 33 // 报错 x的存在p的16个字节的栈里面
p.y = 44 // 报错
let s = Size(width: 10, height: 20) // s的内存不可以改,即s的栈内存8个字节的内存地址不可以变
s = Size(width: 11, height: 22) // 报错,不允许s指向新的内存地址
s.width = 33 // 不报错 可以改内存里面的数据,这些成员的值使存在堆内存的
s.height = 44 // 不报错 可以改内存里面的数据
4. 嵌套类型
用法类似于内部类。
// struct中嵌套枚举
struct Poker {
enum Suit: Character {
case spades = "♠", hearts = "♥", diamond = "♦", clubs = "♣"
}
enum Rank: Int {
case two = 2, three, four
case jack, queen, king , ace
}
}
// 访问 一步步点下去就ok
print(Poker.Suit.hearts.rawValue)
网友评论