SwiftUI - 从架构上讲,逻辑应该放在哪里
SwiftUI - where should logic live architecturally speaking
我是 SwiftUI 的新手,对逻辑应该放在哪里有疑问。显然,由于 SwiftUI 是声明式的并且基于状态,我想避免在 SwiftUI 视图结构中包含大量基于逻辑的代码。但是,在我的示例中,我有一个按钮,当按下该按钮时,应触发以下 POST API 调用:
private func submitIncidentForm(selectedIncident: IncidentReasonResponse) {
showError = false
guard let incidentId = selectedIncident.id else { return }
let args = ["order_id": orderId]
let body = IncidentRequest(reason: incidentId, employeeId: employeeId, pilotMessage: self.comments)
API.client.post(Endpoint.incident, with: args, using: .put, posting: body, expecting: IncidentResponse.self) { success, response in
DispatchQueue.asyncMain {
switch success {
case.success(_):
if let response = response {
self.existingIncidents.append(response)
self.selectedIncident = nil
self.comments = ""
}
case .failure(_, _):
showError = true
}
}
}
}
在理想的 SwiftUI 架构中,它会在何处运行并从何处调用?
第一件事:没有理想的架构。
恕我直言,一个 好的 架构让你有足够的自由以简单的方式表达简单的问题,而不是强迫你写一些胶水 类作用是提供抽象,但随后也增加了复杂性,只是为了分离位于不同文件中的关注点。
尽管如此,在您的情况下,使用 MVVM 或 MVI 模式之一是有意义的。
用户通过点击“提交表单”按钮表达其“意图”,其操作调用函数submit(_ request: IncidentRequest)
:
struct IncidentRequest { ... }
struct IncidentRequestView: View {
let viewState: incidentRequestViewState
let submit: (IncidentRequest) -> Void
@State var incidentRequest: IncidentRequest = .init()
var body: some View {
Button("Submit Form") {
submit(incidentRequest)
}
}
}
闭包submit
和viewState
必须由父视图设置!
请注意,视图本身不处理提交请求。它也不会 也不能 改变它的视图状态,它代表视图呈现自身所需的一切。
视图模型现在最终会收到此“意图”并对其进行处理:
final class IncidentRequestViewModel: ObservableObject {
@Published private(set) var viewState: IncidentRequestViewState = .init()
func submit( _ request: IncidentRequest) {
...
}
}
submit
函数的实现然后会将“提交事件请求”“翻译”为可以发送到模型的合适形式,模型最终负责执行请求。模型更适合发布者,视图模型观察模型。
对于干净的架构,模型将是最终可以执行事件请求的任何具体事物的抽象。也就是说,它不会是一个 API 泄漏实现细节,比如这是一个网络调用,或者你写入 Realm 数据库或 CoreData 等
现在,当您拥有 IncidentRequest 视图、IncidentRequest ViewModel 和 IncidentRequest 模型时,您需要 assemble 这些组件,“某处”。
当您采用像 MVVM 这样的架构时,您将致力于实现这一目标的约定和良好实践。您的团队可能同意使用专用的父视图 (SwiftUI),您可以在其中 assemble 部分:
struct IncidentRequestMainView: View {
@StateObject var viewModel =
IncidentRequestViewModel(model: /* injected */)
var body: some View {
IncidentRequestView(
incidentViewState: viewModel.viewState,
submit: viewModel.submit)
}
}
您可能会注意到,纯技术上处理执行此请求所需的所有操作的实际复杂事物(又名 域逻辑)已移至模型。那也是它属于的地方。
此外,纯视觉逻辑似乎在视图模型中(说 什么 呈现 - 又名 Presentation Logic)和查看(说 如何呈现 )。恕我直言,这也是正确的地方。
最后,有一个专门的组件负责 assemble 所有部分。
我是 SwiftUI 的新手,对逻辑应该放在哪里有疑问。显然,由于 SwiftUI 是声明式的并且基于状态,我想避免在 SwiftUI 视图结构中包含大量基于逻辑的代码。但是,在我的示例中,我有一个按钮,当按下该按钮时,应触发以下 POST API 调用:
private func submitIncidentForm(selectedIncident: IncidentReasonResponse) {
showError = false
guard let incidentId = selectedIncident.id else { return }
let args = ["order_id": orderId]
let body = IncidentRequest(reason: incidentId, employeeId: employeeId, pilotMessage: self.comments)
API.client.post(Endpoint.incident, with: args, using: .put, posting: body, expecting: IncidentResponse.self) { success, response in
DispatchQueue.asyncMain {
switch success {
case.success(_):
if let response = response {
self.existingIncidents.append(response)
self.selectedIncident = nil
self.comments = ""
}
case .failure(_, _):
showError = true
}
}
}
}
在理想的 SwiftUI 架构中,它会在何处运行并从何处调用?
第一件事:没有理想的架构。
恕我直言,一个 好的 架构让你有足够的自由以简单的方式表达简单的问题,而不是强迫你写一些胶水 类作用是提供抽象,但随后也增加了复杂性,只是为了分离位于不同文件中的关注点。
尽管如此,在您的情况下,使用 MVVM 或 MVI 模式之一是有意义的。
用户通过点击“提交表单”按钮表达其“意图”,其操作调用函数submit(_ request: IncidentRequest)
:
struct IncidentRequest { ... }
struct IncidentRequestView: View {
let viewState: incidentRequestViewState
let submit: (IncidentRequest) -> Void
@State var incidentRequest: IncidentRequest = .init()
var body: some View {
Button("Submit Form") {
submit(incidentRequest)
}
}
}
闭包submit
和viewState
必须由父视图设置!
请注意,视图本身不处理提交请求。它也不会 也不能 改变它的视图状态,它代表视图呈现自身所需的一切。
视图模型现在最终会收到此“意图”并对其进行处理:
final class IncidentRequestViewModel: ObservableObject {
@Published private(set) var viewState: IncidentRequestViewState = .init()
func submit( _ request: IncidentRequest) {
...
}
}
submit
函数的实现然后会将“提交事件请求”“翻译”为可以发送到模型的合适形式,模型最终负责执行请求。模型更适合发布者,视图模型观察模型。
对于干净的架构,模型将是最终可以执行事件请求的任何具体事物的抽象。也就是说,它不会是一个 API 泄漏实现细节,比如这是一个网络调用,或者你写入 Realm 数据库或 CoreData 等
现在,当您拥有 IncidentRequest 视图、IncidentRequest ViewModel 和 IncidentRequest 模型时,您需要 assemble 这些组件,“某处”。
当您采用像 MVVM 这样的架构时,您将致力于实现这一目标的约定和良好实践。您的团队可能同意使用专用的父视图 (SwiftUI),您可以在其中 assemble 部分:
struct IncidentRequestMainView: View {
@StateObject var viewModel =
IncidentRequestViewModel(model: /* injected */)
var body: some View {
IncidentRequestView(
incidentViewState: viewModel.viewState,
submit: viewModel.submit)
}
}
您可能会注意到,纯技术上处理执行此请求所需的所有操作的实际复杂事物(又名 域逻辑)已移至模型。那也是它属于的地方。
此外,纯视觉逻辑似乎在视图模型中(说 什么 呈现 - 又名 Presentation Logic)和查看(说 如何呈现 )。恕我直言,这也是正确的地方。
最后,有一个专门的组件负责 assemble 所有部分。