You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 13:06:04