SwiftUI 架构层面而言业务逻辑应当存放于什么位置?
逻辑存放位置:遵循
ObservableObject协议的视图模型 SwiftUI的视图结构体本身仅负责描述UI结构、响应用户交互,不承载业务逻辑。你这段和状态绑定的网络请求逻辑,应该全部放到独立的视图模型类中,所有方法内用到的状态(比如showError、existingIncidents、selectedIncident、comments等)也同步迁移到视图模型内,用@Published标记供视图监听变化。
示例代码如下:
import SwiftUI class IncidentFormViewModel: ObservableObject { // 所有需要和视图交互的状态都用@Published标记 @Published var showError = false @Published var existingIncidents: [IncidentResponse] = [] @Published var selectedIncident: IncidentReasonResponse? @Published var comments = "" let orderId: String let employeeId: String // 初始化时传入必要的业务参数 init(orderId: String, employeeId: String) { self.orderId = orderId self.employeeId = employeeId } // 迁移后的提交逻辑,补充[weak self]避免循环引用 func submitIncidentForm() { showError = false guard let incidentId = selectedIncident?.id else { return } let args = ["order_id": orderId] let body = IncidentRequest(reason: incidentId, employeeId: employeeId, pilotMessage: comments) API.client.post(Endpoint.incident, with: args, using: .put, posting: body, expecting: IncidentResponse.self) { [weak self] success, response in DispatchQueue.main.async { guard let self = self else { return } switch success { case.success(_): if let response = response { self.existingIncidents.append(response) self.selectedIncident = nil self.comments = "" } case .failure(_, _): self.showError = true } } } } }
视图层调用方式
在对应的SwiftUI视图中,用@StateObject(iOS 14+)持有视图模型实例,点击按钮时直接调用视图模型的提交方法即可,视图完全不需要关心内部逻辑实现:
struct IncidentFormView: View { // @StateObject保证视图重绘时不会销毁视图模型实例 @StateObject private var viewModel: IncidentFormViewModel init(orderId: String, employeeId: String) { _viewModel = StateObject(wrappedValue: IncidentFormViewModel(orderId: orderId, employeeId: employeeId)) } var body: some View { Form { // 表单控件直接绑定视图模型的属性 TextField("事件备注", text: $viewModel.comments) // 其他表单控件比如原因选择器等,也绑定到viewModel的对应属性 Button("提交事件") { viewModel.submitIncidentForm() } .disabled(viewModel.selectedIncident == nil) } .alert("提交失败,请稍后重试", isPresented: $viewModel.showError) { Button("知道了", role: .cancel) {} } } }
可选优化建议
- 如果这段网络请求逻辑会在多个页面复用,可以再抽一层独立的服务层,把网络调用封装到
IncidentService类中,视图模型仅调用服务层方法,不需要关心具体的网络实现细节,进一步解耦也方便单元测试。 - 可以把旧的闭包回调异步逻辑换成Swift Concurrency的
async/await写法,代码更简洁,也不需要手动处理DispatchQueue.main.async和内存引用问题。
内容的提问来源于stack exchange,提问作者DevB1
相关产品推荐
相关产品推荐

