聊聊swift「class」与「struct」

25 阅读4分钟

前言

最近公司开了一个新项目, 加上自身也在复习面试相关基础内容, 所以最近又把这个对于swift的最基础的内容拉出来聊一聊.

基础

大部分语言都是有这两种分类的, 引用类型值类型 . Kotlin, Rust, C#, Go, 现代语言们基本都有这样的设计, 虽然用法百花齐放, 但设计理念基本相同, 都是由于计算机本身设计实现构成的.

引用类型 

在Swift中关键字为class

  1. 引用类型:class是引用类型,赋值或传递时只是传递对象的引用,而不是复制对象本身。

  2. 存储在堆上:class的实例存储在堆上,通过引用进行访问。

  3. 手动管理内存:虽然现代编程语言提供了垃圾回收机制,但堆上的内存管理相对栈来说更复杂,需要关注内存泄漏等问题。

值类型

在Swift中关键字为struct, enum, 以及一些基本的数据 StringInt ......

  1. 值类型:每次赋值或传递时都会复制其内容。

  2. 存储在栈上:实例通常存储在栈上,除非它们包含被分配到堆上的引用类型。

  3. 自动管理内存:栈上的内存分配和释放是由编译器自动管理的,操作简单且快速。

另: Swift本身会对值类型引用使用 Copy-on-Write 进行引用优化.

 

callback是什么类型的呢?

普通的回调(callback)是值类型,大部分语言都有尾调用优化。尾调用优化的核心在于通过优化尾递归和尾调用的栈空间使用,通过替换或跳转技术来减少栈深度。

  然而,如果回调作为逃逸闭包存在,那么它就是引用类型了。

故综合来看, 大部分情况下, 以值类型声明能够提高相对的运行效率, 但是生活, 有些时候会遇到一些迫不得已的事情.

引用类型特殊性

通用部分

什么时候一定会用的class呢? 大部分的语言在最初都是一样的.

状态

显而易见的内容是多态继承. 这个是大部分人都能说出来的事情.

同时某些老牌数据结构就是强依赖状态的, 例如 ListNode 或者 TreeNode.

作者曾尝试拿 struct 声明了一下 发现用老算法根本没法写, 能够简单实现一些算法, 但实际效果还不如用Array.

还有些是需要共享状态的, 如单例设计模式、持久化存储, 或者是 ViewController/ ObservableObject 这种东西, 基本都需要用class 声明

额外

那么 Apple Developer 开发环境中, 还有一个相当重要的部分.

那就是兼容OC, 在 Objective-C 语境中, 极大部分都是需要继承 NSObject, 也包括一些 来自于 UIKIt 的相关声明内容.

基本上你想建立一个双方都通用的内容, 那就不用考虑定义struct类型了.

此外呢还有一个内容, 如有类似需要在模型层开一个class的需求(如: Timer, Notification). 那么建议, struct 与 class 分开, 在另一个地方统一管理, 或者将模型层整个改为 class.

值类型特殊性

值类型有很多优点, 但是在我看来, 它是近代才出现的内容, 很多的教程, 经典的名著, 其实对其都没有很深入的剖析, 再加上很多语言也没有值类型的相关定义. 那么就造成了如今的效果「上手难度较高」.

那么聊到了值类型, 就不得不说出他的亲兄弟, 函数式编程.

class 倒是也能写, 但是可以很负责任的跟你说, 很卡手. 值类型天生就被定义了, 它每次都需要重新被赋值, 非常符合函数式这种无状态, 无副作用的书写习惯.

相比其他编程语言, Swift在值类型这方面通过协议(protocol)进行了相关逻辑的复用. 协议可以定义一组方法和属性, 然后让值类型(如struct和enum)来遵循这些协议, 从而实现多态和代码复用. 相关协议的部分应该会另起一个文章来写, 毕竟算是swift中的重中之重.

总结

文章简单聊了聊swift中的引用类型与值类型, 主要是提及在实际开发中的相关处理, 算作是开发的经验之谈, 这部分属于swift基础中的基础, 但不积跬步无以至千里. 愿有所收获, 祝 Coder 能 Happy Coding.