Swift: 类与结构体(上)--(零基础教程)

178 阅读3分钟

一、初识类与结构体

对于类与结构体我们需要区分的第一件事就是:

类是引用类型。也就意味着一个类类型的变量并不直接存储具体的实例对象,是对当前存储具体实例内存地址的引用。

有引用类型,就有值类型,最典型的就是 Struct ,结构体的定义也非常简单,相比较 类类型的变量中存储的是地址,那么值类型存储的就是具体的实例(或者说具体的值)。
struct/class LGTeacher{
var age: Int
var name: String
init(age: Int, name: String) {
    self.age = age
    self.name = name 
}
deinit{
} 
}

结构体和类的主要相同点有:

1.定义存储值的属性
2.定义方法
3.定义下标以使用下标语法提供对其值的访问
4.定义初始化器
5.使用 extension 来拓展功能
6.遵循协议来提供某种功能

主要的不同点有:

1.类有继承的特性,而结构体没有
2.类型转换使您能够在运行时检查和解释类实例的类型 
3.类有析构函数用来释放其分配的资源\
4.引用计数允许对一个类实例有多个引用

另外引用类型和值类型还有一个最直观的区别就是存储的位置不同:一般情况,值类型存储的在 栈上,引用类型存储在堆上。


![WX20211227-172729@2x.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f795c6ba1dde42b18c7dbc0d311061ee~tplv-k3u1fbpfcp-watermark.image?)
栈区(stack): 局部变量和函数运行过程中的上下文\
Heap: 存储所有对象\
Global: 存储全局变量;常量;代码区\
Segment & Section: Mach-O 文件有多个段( Segment ),每个段有不同的功能。然后每 个段又分为很多小的 Section

二、类的初始化器

当前的类编译器默认不会自动提供成员初始化器,但是对于结构体来说编译 器会提供默认的初始化方法(前提是我们自己没有指定初始化器)!

struct LGTeacher{ 
    var age: Int
    var name: String
}

Swift 中创建类和结构体的实例时必须为所有的存储属性设置一个合适的初始值。所以 类 LGPerson 必须要提供对应的指定初始化器,同时我们也可以为当前的类提供便捷初 始化器(注意:便捷初始化器必须从相同的类里调用另一个初始化器。)

class LGPerson{ 
var age: Int
var name: String
init(_ age: Int, _ name: String) {
    self.age = age
    self.name = name
}
convenience init() { self.init(age: 18, name:"Kody")

} }
  • 指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。
  • 指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做,指定初始化器赋予的新值将被父类中的初始化器所覆盖
  • 便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括 同类里定义的属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖。
  • 初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用 self 作为值。

可失败初始化器: 这个也非常好理解,也就意味着当前因为参数的不合法或者外部条件 的不满足,存在初始化失败的情况。这种 Swift 中可失败初始化器写 return nil 语句, 来表明可失败初始化器在何种情况下会触发初始化失败。写法也非常简单:

class LGPerson{ 
    var age: Int
    var name: String
    init?(_ age: Int, _ name: String) {
        if(age < 18){return nil}
        self.age = age
        self.name = name
}
convenience init?() { self.init(age: 18, name:"Kody")
} }

必要初始化器:在类的初始化器前添加 required 修饰符来表明所有该类的子类都必须 实现该初始化器