如何为Worksheet结构体设计继承式数据模型以复用视图与函数?
高效复用Worksheet类型的实现方案需求
我有多种Worksheet结构体,用于填充视图供用户填写内容后保存。此前单独使用每个结构体,现在希望设计一套包含**公共属性(id、date)**的抽象方案,复用视图与函数,避免为每种Worksheet单独创建重复代码。
原本读取某类Worksheet数据的代码如下:
if let diaryArray = vm.readData(of: [Diary](), from: "diary_data") { let sortedArray = diaryArray.sorted(by: {$0.date > $1.date}) vm.diaries = sortedArray }
我希望将其改写为泛型形式,无需提前知晓具体Worksheet类型,只需确认它包含date属性即可按此排序:
if let diaryArray = vm.readData(of: [T](), from: "\(path)_data") { let sortedArray = diaryArray.sorted(by: {$0.date > $1.date}) vm.worksheets = sortedArray }
我尝试了两种实现方式,但都存在问题:
1. 协议方式
先定义包含公共属性的协议,让所有Worksheet结构体遵循该协议:
protocol Worksheet: Codable, Identifiable, Hashable { var id: String { get set } var date: Date { get set } } extension Worksheet { static func parseVehicleFields(id: String, date: Date) -> (String, Date) { let id = "" let date = Date() return (id, date) } } struct Diary: Worksheet { var id: String var date: Date var title: String var situation: String var thoughts: String var emotions: String var physicalSensations: String var behaviours: String var analysis: String var alternative: String var outcome: String init() { self.id = "" self.date = Date() self.title = "" self.situation = "" self.thoughts = "" self.emotions = "" self.physicalSensations = "" self.behaviours = "" self.analysis = "" self.alternative = "" self.outcome = "" } } struct Goal: Worksheet { var id: String var date: Date var mainGoal: String var notificationActive: Bool var notificationDate: Date var obstacles: String var positiveBehaviours: String var immediateActions: String var goalAchieved: Bool init() { self.id = "" self.date = Date() self.mainGoal = "" self.notificationActive = false self.notificationDate = Date() self.obstacles = "" self.positiveBehaviours = "" self.immediateActions = "" self.goalAchieved = false } }
遇到的问题
尝试使用[any Worksheet]作为类型读取数据时,编译报错:'Type 'any Worksheet' cannot conform to 'Decodable''
if let array = vm.readData(of: [any Worksheet](), from: "\(path)_data") { let sortedArray = array.sorted(by: {$0.date > $1.date}) vm.worksheets = sortedArray }
配套的保存函数是泛型实现,传入具体类型(如Diary)时能正常运行,但这种写法失去了泛型复用的意义:
func saveWorksheetProtocol<T: Worksheet>(for type: [T], to path: String) { let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first let documentURL = (directoryURL?.appendingPathComponent(path).appendingPathExtension("json"))! let jsonEncoder = JSONEncoder() let data = try? jsonEncoder.encode(type) do { try data?.write(to: documentURL, options: .noFileProtection) } catch { print("Error...Cannot save data!!!See error: \(error.localizedDescription)") } }
2. 嵌套结构体方式
将所有Worksheet类型嵌套到一个主结构体中:
struct Worksheet: Codable, Identifiable, Hashable { var id: String var date: Date var diary: Diary? var goal: Goal? var experiment: Experiment2? init() { self.id = "" self.date = Date() self.diary = Diary() self.goal = Goal() self.experiment = Experiment2() } } struct Diary: Codable, Hashable { var title: String var situation: String var thoughts: String var emotions: String var physicalSensations: String var behaviours: String var analysis: String var alternative: String var outcome: String init() { self.title = "" self.situation = "" self.thoughts = "" self.emotions = "" self.physicalSensations = "" self.behaviours = "" self.analysis = "" self.alternative = "" self.outcome = "" } } struct Goal: Codable, Hashable { var mainGoal: String var notificationActive: Bool var notificationDate: Date var obstacles: String var positiveBehaviours: String var immediateActions: String var goalAchieved: Bool init() { self.mainGoal = "" self.notificationActive = false self.notificationDate = Date() self.obstacles = "" self.positiveBehaviours = "" self.immediateActions = "" self.goalAchieved = false } }
遇到的问题
- 若子结构体为非可选类型,会产生冗余数据:比如仅需
Diary条目时,仍需持有空的Goal、Experiment2实例 - 若将子类型设为可选类型,使用
Binding时会出现无法解析的解包错误,即使提前判断过实例是否存在:
TextField("", text: $entry.diary!.title, axis: .vertical) // 此处报错 .lineLimit(20) .disabled(!editMode)
现寻求高效处理Worksheet类型的方案,以减少视图与函数的重复代码。
内容的提问来源于stack exchange,提问作者Peter Ruppert
相关产品推荐
相关产品推荐

