决定了数据存储方式和模型行为
概括
结构体和类是app中数据存储和建模的理想选择,但两者相似性导致不好选择出最合适的。
以下是app新增数据类型时候合理选择的建议:
-
默认优先用结构体
-
考虑兼容OC时用类
-
需要控制数据身份时用类
-
用结构体和协议实现共享
默认用结构体
用结构去代表大部分数据。Swift中结构体包含了其他语言中对类有限制的特性: 可包括存储属性,计算属性,方法。不仅如此,Swift 结构体可通过遵守协议得到一个默认已经实现了的行为。Swift标准库和Foundations中我们经常使用的string,array,dictionary都是结构体。
无需关心App整体状态,用结构体可以更容易的在局部理解代码。因为结构体是值类型而非像class一样的引用类型,除非有意为之,结构体本体改变在app的其他把部分不会被表现出来。这允许我们l看到一段代码时更加自信的说:这里对实例修改的影响是明确可知的,而不需要去担心纵向函数调用产生的影响。
考虑兼容OC时使用类
如需用一个OC API处理数据,或需继承自已有的OC framwork类,你需用类和类继承进行数据建模。比如很多OC framwork暴露出很多类供我们继承。
需要控制数据Identity时使用类
Swift中的类具有内置的标识概念,因为它们是引用类型。这意味着当两个不同的类实例的每个存储属性具有相同的值时,它们仍被身份运算符(===)视为不同。这也意味着一个共享实例的修改在app其他引用了此实例的代码都是有效的。在需要实例有这样特性的时候使用类。常见的情况有 file handles, network connections 或者像 CBCentralManager这样的共享中介。
比如有一个代表本地数据库的中间者,全局app来看,这个数据库的访问控制代码需要完全控制这个数据库的所有状态,这时类合适,但要保证对数据库的访问设置限制了那个部分拥有权限。
重要
谨慎使用此特性。普遍使用共享类提高了发生逻辑错误的概率。修改一个高度共享实例的可能产生的严重后果总是被低估的,所以这种情况下要注意正确的编码。
不需控制Identity时用结构体
数据建模时,如果我们不控制数据包含的实体的dentity信息,使用结构体。
比如,app和远程服务器交互的时候,一个实例的唯一标识可能被外部实例完全拥有,并通过一个ID进行通信。如果app模型的共性存储在服务器上,可以通过这些标识符选择结构体建模记录。现在的例子
jsonResponse包含了来自服务器的一个被编码的PenPalRecord
struct PenPalRecord {
let myID: Int
var myNickname: String
var recommendedPenPalID: Int
}
var myRecord = try JSONDecoder().decode(PenPalRecord.self, from: jsonResponse)
本地更改像PenPalRecord这样的模型类型是有好用的。例如,应用可能会推荐多个不同的笔友以响应用户反馈。 由于PenPalRecord结构不控制底层数据库记录的标识,因此对本地PenPalRecord实例所做的更改不会意外更改数据库中的值。
这段不懂:
If another part of the app changes myNickname and submits a change request back to the server, the most recently rejected penpal recommendation won't be mistakenly picked up by the change. Because the myID property is declared as a constant, it can't change locally. As a result, requests to the database won't accidentally change the wrong record.
结构体配合协议实现继承和共享需求
结构体和类都支持形式上的继承。结构体和协议只能继承协议,它们不能继承类。但是类的层级继承形式也可以使用结构体配合协议做到。
如果从你头开始构建继承关系,则首选协议继承。 Protocols允许类,结构和枚举参与继承,而类继承只与其他类兼容。 当你选择如何建模数据时,首先尝试使用协议继承构建数据类型的层次结构,然后使用结构体遵守这些协议。
摘自:https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes
网友评论