我试图使用一个@ObservableObject viewModel,它在我的视图结构中被声明为@ObservedObject。问题是,当viewModel更改它的“domains”属性@Published var时,UI不会更新。另外,我在init(){}中调用的getDomains()函数中更改域。它被称为两次,为什么会发生这种情况?下面是我的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)
}
}
}
}
视图代码:导入Foundation导入SwiftUI导入合并
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)
}
}
}
有人能帮帮我吗?谢谢.
3条答案
按热度按时间vs91vp4v1#
DomainsOfInterestView
在其视图模型的每次更新时都会重新创建。每次都用新的DomainsViewModel
示例初始化视图模型属性。新的视图模型将domains
属性设置为[InterestDomain]()
,并将再次调用self.getDomains
。首先,最好在初始化器中将viewModel注入到
DomainsOfInterestView
中,正如@youjin在上一篇文章的评论中所写的那样。此外,如果您的最低部署目标允许,您可以使用@StateObject
而不是@ObservedObject
。在这种情况下,viewModel
属性不会在每次更新视图时重置。vaqhlq812#
ForEach
是一个View
,而不是传统的for循环。将您的模型设置为Identifiable
,并将ForEach
更改为:此外,你的fetcher必须是
@StateObject
,否则它会在每次重新初始化DomainsOfInterestView
时丢失。您的获取对象缺少取消支持。你可以通过将fetcher对象更改为
.task
来自动获得它,例如。hyrbngr73#
引用here的答案
如果你的数据可以改变,你需要一个动态的ForEach循环(带有一个显式的id参数):
在某些情况下,当你试图修改ForEach循环中使用的数组时,Xcode会警告你:
ForEach(:content:)应该只用于常量数据。相反,请将数据符合Identifiable或使用ForEach(:id:content:)并提供显式id!
测试代码
在iOS 14 beta 6上使用Xcode 12 beta 6进行测试