[英]How to declare different structs inside one array in Swift
Is it possible to create an array of different structs?是否可以创建一个不同结构的数组? My data structure looks like this:我的数据结构如下所示:
enum MovementType: String, Codable {
case WeightMovement
case RepsMovement
}
struct Movement: Identifiable, Codable {
let id: UUID = UUID()
let name: String
let type: MovementType
let workouts: [WeightMovement, RepsMovement] ---> A solution for this line based on the Type above
}
struct WeightMovement: Identifiable, Codable {
let id: UUID = UUID()
let weight: Double
let sets: Int
let reps: Int
}
struct RepsMovement: Identifiable, Codable {
let id: UUID = UUID()
let sets: Int
let reps: Int
let seconds: Int
}
A brief example of what is should do: A user can create multiple movements with a name and movementType.应该做什么的一个简短示例:用户可以使用名称和运动类型创建多个运动。 A user can add workouts to a movement but since each movementType holds different data i create different structs for that.用户可以将锻炼添加到运动中,但由于每个运动类型包含不同的数据,因此我为此创建了不同的结构。
ideally the array will always hold only one type of Movement based on the type
of the movement.理想情况下,该数组将始终根据运动type
仅保存一种运动类型。
The easiest method would be to declare the properties whose presence is uncertain as optional and create a common struct
that combines both of the optional properties.最简单的方法是将其存在不确定的属性声明为可选的,并创建一个组合两个可选属性的通用struct
。 Since we already have a MovementType
that would provide certainty about the availability of a particular property we could probably force-unwrap, although safe-unwrap is safer at any point.由于我们已经有一个MovementType
可以确定特定属性的可用性,我们可能可以强制解包,尽管安全解包在任何时候都更安全。
struct Movement: Identifiable, Codable {
var id: UUID = UUID()
let name: String
let type: MovementType
let workouts: [MovementDetail]
}
struct MovementDetail: Identifiable, Codable {
var id: UUID = UUID()
let weight: Double?
let sets: Int
let reps: Int
let seconds: Int?
}
enum MovementType: String, Codable {
case WeightMovement
case RepsMovement
}
I would do it this way:我会这样做:
struct Movement: Identifiable, Codable {
var id: UUID = UUID()
var name: String
var type: MovementType
var weightWorkouts: [WeightMovement]
var repsWorkouts: [RepsMovement]
var workouts: [Codable] {
switch type {
case .WeightMovement:
return weightWorkouts
case .RepsMovement:
return repsWorkouts
}
}
}
This doesn't do exactly what you describe, as there are multiple array types on the struct, but for the object's consumer, you have access to a single property workouts
that will return one of multiple possible types.这并不完全符合您的描述,因为结构上有多种数组类型,但对于对象的使用者,您可以访问单个属性workouts
,它将返回多种可能类型中的一种。
As Tushar points out in his comment, though, it is fragile to specify what the return type is in two different places ( type
and the actual type returned in the array).但是,正如 Tushar 在他的评论中指出的那样,在两个不同的地方( type
和数组中返回的实际类型)指定返回类型是很脆弱的。 A subclass or protocol would probably be better.子类或协议可能会更好。
ideally the array will always hold only one type of Movement based on the type of the movement.理想情况下,该数组将始终根据运动类型仅保存一种运动类型。
In this case I recommend to decode the JSON manually and declare the type enum with associated types在这种情况下,我建议手动解码 JSON 并使用关联类型声明类型枚举
enum MovementType {
case weight([WeightMovement])
case reps([RepsMovement])
}
struct Movement: Identifiable, Decodable {
private enum CodingKeys : String, CodingKey { case name, type, workouts }
let id: UUID = UUID()
let name: String
let type: MovementType
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
let movementType = try container.decode(String.self, forKey: .type)
switch movementType {
case "WeightMovement":
let workouts = try container.decode([WeightMovement].self, forKey: .workouts)
type = .weight(workouts)
case "RepsMovement":
let workouts = try container.decode([RepsMovement].self, forKey: .workouts)
type = .reps(workouts)
default: throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "Invalid movement type")
}
}
}
struct WeightMovement: Identifiable, Decodable {
let id: UUID = UUID()
let weight: Double
let sets: Int
let reps: Int
}
struct RepsMovement: Identifiable, Decodable {
let id: UUID = UUID()
let sets: Int
let reps: Int
let seconds: Int
}
The explicit UUID assignment implies that id
is not going to be decoded.显式的 UUID 分配意味着id
不会被解码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.