编程iOS开发者

结构体(struct)在Swift中如何工作,它们与类(class)在存储和行为方面有什么区别,以及为什么结构体通常用于数据建模?

用 Hintsage AI 助手通过面试

回答。

问题的背景

在Swift中,从一开始就强调了值类型——结构体(struct)作为数据建模的主要工具。与Objective-C中一切都是对象(类)不同,Swift鼓励对简单模型、数据和小型业务对象使用结构体。

问题

许多开发者,尤其是有其他面向对象语言经验的,错误地将类用于所有场合。这会导致内存问题(引用循环)、在传递对象时的意外更改以及线程安全方面的复杂性,因为类是引用类型。

解决方案

Swift中的结构体是值类型,在赋值和传递给函数时会被复制,与类(引用类型)传递引用不同。这使得结构体在没有复杂生命周期和继承逻辑的模型中更受欢迎。

代码示例:

struct Point { var x: Int var y: Int } var p1 = Point(x: 10, y: 20) var p2 = p1 p2.x = 30 // p1.x仍然等于10

关键特性:

  • 结构体的复制始终会导致值的复制(值语义)
  • 更少的内存泄漏机会
  • 不支持继承,仅支持协议

引导思考的问题。

结构体可以有继承吗(subclass)?

不,Swift中的结构体不支持继承。所有行为扩展仅通过协议和扩展实现。

这是否意味着结构在传递给函数时总是会被复制?

实际上,Swift使用了按需复制(Copy-On-Write)优化。如果我们不改变结构,它不会被复制,只有在更改时才会创建副本。这适用于标准集合和复杂结构。

var arr1 = [1, 2, 3] var arr2 = arr1 arr2.append(4) // 只有在这里发生复制

在什么情况下不能使用结构体?

  • 如果需要身份(对象,按引用比较)
  • 如果需要继承
  • 如果必须是唯一实例(单例)

常见错误和反模式

  • 对简单模型和数据结构使用类
  • 在结构中存储引用类型并尝试复制它们
  • 期望通过“引用”传递结构并尝试通过结构改变外部对象

生活示例

消极案例

使用类来存储同类数据(例如,为地图上的点),结果是由于频繁访问内存导致性能下降、复杂的内存管理和引用混淆的bug。

优点:

  • 能够存储为AnyObject的数组

缺点:

  • 性能较低
  • 线程安全性有问题
  • 内存管理问题

积极案例

使用结构体来处理安全复制的数据模型,不会导致泄漏且不具备多余的复杂性。

优点:

  • 简单,复制安全
  • 不存在引用循环
  • 易于测试

缺点:

  • 不能实现需要继承的模式
  • 如果在结构内有引用类型,复制和更改时可能会出现惊讶