Swift类与结构体

267 阅读3分钟

Swift开发中类与结构体可以说是使用频率很高的,两者看起来很相似。下面我们来看下两者的相同点和不同点及使用过程中的注意点。

struct Teacher{
    var age:Int
    var name:String
}
class Teacher{
    var age:Int
    var name:String
    //初始化
    init(age:Int, name:String) {
        self.age = age
        self.name = name
    }
}

一、类与结构体相同点

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

二、类与结构体不同点

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

三、初始化器

类不会默认提供成员初始化方法,结构体会提供默认的初始化方法(前提是我们自己没有指定初始化器)。

struct Teacher{
    var age:Int
    var name:String
}
//可以使用如下默认方法初始化
var t = Person(age: <Int>, name:<String>)

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

class Person{ 
  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")
  } 
}

注意点:

  • 指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。
class Person{
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}
class Teacher:Person{
    var subName: String
    init(subName: String)
    {
    //需要设置完subName 才可以调用父类初始化
        self.subName = subName
        super.init(age: 20, name: "Tom")
    }
}
  • 指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做,指定初始化器赋予的新值将被父类中的初始化器所覆盖。
class Person{
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}
class Teacher:Person{
    override init(age: Int, name: String) {
    //需要先调用父类初始化方法
        super.init(age: age, name: name)
        self.age = age
        self.name = name
    }
}
  • 便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括 同类里定义的属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖。

  • 初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用 self 作为值。

  1. 可失败初始化器: 这个也非常好理解,也就意味着当前因为参数的不合法或者外部条件 的不满足,存在初始化失败的情况。这种 Swift中可失败初始化器写 return nil 语句,来表明可失败初始化器在何种情况下会触发初始化失败。写法也非常简单:
class Person{
    var age:Int
    var name:String
    //可失败 初始化
    init?(age:Int, name:String) {
        if age < 18 return nil
        self.age = age
        self.name = name
    }
}
  1. 必要初始化器:在类的初始化器前添加 required 修饰符来表示所有该类的子类都必须实现该初始化器。
class Person{
    var age:Int
    var name:String
    //必要 初始化
    required init(age:Int, name:String) {
        self.age = age
        self.name = name
    }
}

四、Swift编译过程:Swift 通过 Swift 编译器编译成 IR,然后在生成可执行文件。 1.jpg

// 分析输出AST
swiftc main.swift -dump-parse

// 分析并且检查类型输出AST 
swiftc main.swift -dump-ast

// 生成中间体语言(SIL),未优化 
swiftc main.swift -emit-silgen

// 生成中间体语言(SIL),优化后的
swiftc main.swift -emit-sil

// 生成LLVM中间体语言 (.ll文件) 
swiftc main.swift -emit-ir

// 生成LLVM中间体语言 (.bc文件) 
swiftc main.swift -emit-bc

// 生成汇编
swiftc main.swift -emit-assembly

// 编译生成可执行.out文件 
swiftc -o main.o main.swift

五、Swift对象初始化及内存分配:

swift源码下载地址 github.com/apple/swift…

  • _allocating_int --> swift_allocObject --> swift_allocObject --> swift_slowAlloc -->Malloc

  • Swift 对象的内存结构 HeapObject (OC objc_object) ,有两个属性: 一个是 Metadata ,一个是 RefCount ,默认占用 16 字节大小。