如何在 SwiftUI 中声明 viewModel 对象? [英] How should the viewModel object be declared in SwiftUI?
问题描述
我正在尝试使用在我的视图结构中声明为 @ObservedObject 的 @ObservableObject viewModel.问题是当 viewModel 改变它的域"时.属性@Published var,UI 未更新.另外,我更改了在 init() {} 中调用的 getDomains() 函数内的域.看起来它被调用了两次,为什么会发生这种情况?这是我的 viewModel 代码:
I am trying to use an @ObservableObject viewModel which is declared as @ObservedObject inside my view struct. The problem is that when the viewModel changes it's "domains" property @Published var, the UI is not updating. Also, I change domains inside getDomains() function which is called inside init() {}. Looks like it is called twice, why is that happening? Here's my code for viewModel:
import Combine
class DomainsViewModel: ObservableObject {
@Published var domains: [InterestDomain] = [InterestDomain]()
init() {
self.getDomains { (response) in
print(response)
}
}
func getDomains(completion: @escaping (Bool) -> Void) {
NetworkEngine.shared.appNetwork.getInterestDomains { result in
self.domains.removeAll()
switch result {
case .success(let domainsOfInterest):
if let domainsList = domainsOfInterest {
self.domains = domainsList
}
completion(true)
case .failure(_):
completion(false)
}
}
}
}
视图代码:进口基金会导入 SwiftUI导入组合
Code for the view: import Foundation import SwiftUI import Combine
struct DomainsOfInterestView: View {
@ObservedObject var viewModel: DomainsViewModel = DomainsViewModel()
@State var isActive = true
var body: some View {
VStack(alignment: .center) {
HStack {
Text("Choose domains of interest for your profile")
.font(.headline)
Spacer()
}.padding(.bottom, 16)
ForEach(viewModel.domains.indices) { index in
DomainOfInterestElement(isActive: self.$isActive, domain: self.viewModel.domains[index].name)
}
OrangeButton(action: {
}) {
Text("Save")
}.padding(.top, 30)
.padding([.leading, .trailing], 30)
Spacer()
}.padding([.leading, .trailing], 12)
.navigationBarTitle("Domains of interest")
}
}
struct DomainsOfInterestView_Previews: PreviewProvider {
static var previews: some View {
DomainsOfInterestView()
}
}
struct DomainOfInterestElement: View {
@Binding var isActive: Bool
var domain: String
var body: some View {
Button(action: {
self.isActive.toggle()
}) {
VStack {
Divider().padding(.bottom, 12)
HStack {
checkBoxView()
.frame(width: 36, height: 36)
textView().font(.custom("SFProDisplay-Regular", size: 16))
Spacer()
}
}
}
}
func checkBoxView() -> Image {
switch isActive {
case true:
return Image(uiImage: #imageLiteral(resourceName: "check-box-active-2-1")).renderingMode(.original)
case false:
return Image(uiImage: #imageLiteral(resourceName: "check-box-active-1")).renderingMode(.original)
}
}
func textView() -> Text {
switch isActive {
case true:
return Text(domain)
.foregroundColor(.black)
case false:
return Text(domain)
.foregroundColor(Color.orGrayColor)
}
}
}
有人可以帮我吗?谢谢.
Could anyone help me please? Thanks.
推荐答案
DomainsOfInterestView
在其视图模型的每次更新时重新创建.并且每次都使用新的 DomainsViewModel
实例初始化视图模型属性.一个新的视图模型会将 domains
属性设置为 [InterestDomain]()
并且 self.getDomains
将被再次调用.
DomainsOfInterestView
is recreated on every update of its view model. And you initialise the view model property with a new DomainsViewModel
instance every time. A new view model will have the domains
property set to [InterestDomain]()
and self.getDomains
will be called again.
首先,最好将 viewModel 注入到初始化器中的 DomainsOfInterestView
,正如@youjin 在上一篇文章的评论中所写的那样.此外,如果您的最低部署目标允许,您可以使用 @StateObject
而不是 @ObservedObject
.在这种情况下,每次更新视图时都不会重置 viewModel
属性.
First of all, better to inject the viewModel to DomainsOfInterestView
in an initiailiser as @youjin wrote in a comment to the previous post. Also, you can use @StateObject
instead of @ObservedObject
if your minimum deployment target allows that. In this case, the viewModel
property won't be reset every time the view is updated.
这篇关于如何在 SwiftUI 中声明 viewModel 对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!