确定如何存储数据和模型行为。
总览
结构体
和 类
是在应用程序中存储数据和模型行为的不错选择,但是 结构体
和 类
的相似性使其很难选择。
在向你的应用程序添加数据类型时,可以参考以下建议:
- 默认情况下使用
结构体
。Default
- 需要
Objective-C
互操作性时,请使用类
。 - 需要控制数据模型的
同一性
时,请使用类
。 - 需要通过
协议继承
共享行为实现
时,请使用结构体
。
一、 默认选择结构体
使用 结构体
表示常见数据类型。Swift
中的 结构体
包含许多功能,这些功能仅限于其他语言中的类:它们可以包含存储属性,计算属性和方法。而且,Swift
结构体
可以通过遵守协议来获得默认的实现行为。Swift
标准库和 Foundation
中对经常使用的数据类型都是用 结构体
实现的,例如数字,字符串,数组和字典。
使用 结构体
可以更轻松地推理代码片段,而无需考虑应用程序的整体状态。由于 结构体
是值类型(与 类
不同),因此对 结构体
的局部更改对应用程序的其余部分不可见,除非您有意将这些更改作为应用程序流程的一部分进行交流。结果,您可以查看一段代码,并更有信心对该部分中的实例进行显式更改,而不是通过与切向相关的函数调用进行不可见的更改。
二、需要与Objective-C互操作性时使用类
如果您使用需要处理数据的 Objective-C
API
,或者需要适应你的数据模型为继承或者定义在 Objective-C
框架中的类,则可能需要使用 类
和 类继承
来对数据进行建模。例如,许多 Objective-C
框架都公开了您希望子类化的类。
三、需要控制同一性时使用类
Swift
中的类带有内置的同一性
概念,因为它们是 引用类型
。这意味着当两个不同的类实例为其每个存储的属性具有相同的值时,同一运算符(===
)仍将它们视为不同。这也意味着,当您在应用程序中共享一个类实例时,对该实例所做的更改对于包含对该实例的引用的代码的每一部分都是可见的。当您需要实例具有这种 同一性
时,请使用 类
。常见的用例是文件管理,网络连接和共享的硬件中介,如CBCentralManager。
例如,如果您有一个表示本地数据库连接的类型,则用于管理对该数据库访问权限的代码需要完全控制从应用程序查看的数据库状态。在这种情况下,使用一个 类
是适当的,但是一定要限制应用程序的哪些部分可以访问共享数据库对象。
重要
小心对待同一性。在整个应用程序中普遍共享类实例使逻辑错误更有可能发生。您可能不会预期更改大量共享实例的后果,因此,正确编写此类代码需要做更多的工作。
四、当您不控制同一性时使用结构体
当你的数据模型包含的信息不需要 同一性
时,请使用 结构体
。
例如,在查询远程数据库的应用中,实例的同一性可以完全由外部实体拥有,并可以通过标识符进行通信。如果应用程序模型的一致性存储在服务器上,则可以将记录建模为带有标识符的结构体。在下面的示例中,jsonResponse
包含来自服务器的编码 PenPalRecord
实例:
struct PenPalRecord {
let myID: Int
var myNickname: String
var recommendedPenPalID: Int
}
var myRecord = try JSONDecoder().decode(PenPalRecord.self, from: jsonResponse)
像 PenPalRecord
模型类型的本地更改是非常有用的。例如,一个应用可能会响应用户反馈而推荐多个不同的 penpals
。因为该PenPalRecord
结构体无法控制基础数据库记录的 同一性
,所以不存在对本地 PenPalRecord
实例所做的更改意外更改数据库中值的风险。
如果应用程序的另一部分发生更改 myNickname
,并将更改请求提交给服务器,则更改不会错误地接受最近拒绝的penpals
建议。因为该 myID
属性被声明为常量,所以不能在本地更改。因此,对数据库的请求不会意外更改错误的记录。
五、使用结构体和协议建模来继承和共享行为
结构体
和 类
都支持一种 继承
形式。结构体和协议只能采用协议;他们不能从类继承。但是,还可以使用协议继承和结构体对可以使用类继承构建的继承层次结构体进行建模。
如果要从头开始建立继承关系,则最好使用协议继承。协议允许类,结构体和枚举参与继承,而类继承仅与其他类兼容。当您选择如何对数据建模时,请先尝试使用协议继承构建数据类型的层次结构体,然后在结构体中采用这些协议。
翻译自官方Swift文档:Choosing Between Structures and Classes
网友评论