Swift 类与结构体

一. 类和结构体的比较

swift中的类:

class LLPerson {
    var age: Int
    var name: String
    
    init(_ age: Int, _ name: String) {
        self.age = age
        self.name = name
    }
}

var person = LLPerson(18, "LL")
var person1 = person

swift 中的结构体:

struct LGTeacher{
    var age: Int
    var name: String

    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}

var t = LGTeacher(age: 18, name: "Kody")
var t1 = t

类和结构体主要相同点:

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

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

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

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

实例内存地址的引用
 
swift中有引用类型,就有值类型,最典型的就是 Struct ,结构体的定义也非常简单,相比较
类类型的变量中存储的是地址,那么值类型存储的就是具体的实例.
另外引用类型和值类型还有一 个最直观的区别就是存储的位置不同: 般情况,值类型存储的在
栈上,引用类型存储在堆上
可以借助两个指令来查看当前变量的内存结构
po : p po 的区别在于使用 po 只会输出对应的值,而 p 则会返回值的类型以及命令结果
的引用名。
x/8g: 读取内存中的值 (8g: 8 字节格式输出 )

二. 类的初始化器

需要注意的 点是:当前的类编译器默认不会自动提供成员初始化器,但是对于结构体来说编译
器会提供默认的初始化方法(前提是我们自己没有指定初始化器)!
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(18, "Kody")
    }
}
当我们派生出一 个子类 LGTeacher ,并指定 个指定初始化器之后会出现什么问题

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

可失败初始化器:

这种 Swift 中可失败初始化器写 return nil 语句,来表明可失败初始化器在何种情况下会触发初始化失败。

必要初始化器:

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

三. 类的生命周期

iOS开发的语言不管是OC还是Swift后端都是通过LLVM进行编译的
 
  • OC 通过 clang 编译器,编译成 IR,然后再生成可执行文件 .o(这里也就是我们的机器码)
  • Swift 则是通过 Swift 编译器编译成 IR,然后在生成可执行文件

分析输出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 对象内存分配
__allocating_init -----> swift_allocObject -----> swift_allocObject -----> swift_slowAlloc -----> Malloc
Swift 对象的内存结构 HeapObject (OC objc_object) ,有两个属性: 一个是 Metadata ,一个是 RefCount ,默认占用 16 字节大小。
经过访问源码可得出以下结构:
类结构:

metadata结构:

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Swift 中的结构体(struct)都是用来封装数据和方法的型,但它们有一些区别。 1. 继承:支持继承(inheritance),可以继承其他的特性,而结构体不支持继承。 2. 引用型和值型:是引用型(reference type),结构体是值型(value type)。当你创建一个的实例并将其分配给变量或常量时,这个变量或常量实际上是对实例的引用。而当你将一个结构体分配给变量或常量时,这个变量或常量会包含该结构体的副本。因此,当你对引用型进行操作时,对该型的所有引用都会受到影响。而对于值型,每个实例之间是独立的,操作一个实例不会影响其他实例。 3. 构造函数:有自己的构造函数(initializer),而结构体的构造函数是自动生成的。在中,你可以指定一个或多个构造函数来初始化的实例。但是结构体的构造函数是根据结构体的属性自动生成的,你也可以自定义结构体的构造函数。 4. Deinitializer:有自己的析构函数(deinitializer),而结构体没有析构函数。 5. 内存管理:Swift 中的使用引用计数(reference counting)来管理内存,而结构体则是在栈上分配内存。由于引用型是在堆上分配内存,所以需要更多的内存管理,包括对象引用计数的增加和减少等操作。 总之,结构体都有其自己的优缺点,根据实际情况选择使用哪种型来封装数据和方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值