我正在尝试从View内部.onAppear()中的viewModel中调用方法。该方法执行后,看起来数据已删除。我看到不到1秒钟的时间即可正确显示数据,但是此后UI仍未显示任何内容并且数据为空。如果我在按钮内调用该数据,则它可以正常工作,完全没有问题。您能帮我吗,onAppear()内的调用方法有什么问题?这是我的视图代码:
struct DomainsOfInterestView: View {
@EnvironmentObject var userProfile: UserProfile
@ObservedObject var viewModel: DomainsViewModel = DomainsViewModel()
var body: some View {
VStack(alignment: .center) {
HStack {
Text("Choose domains of interest for your profile")
.foregroundColor(Color.orGrayColor)
.font(.custom("SFProDisplay-Regular", size: 16))
Spacer()
}.padding([.bottom, .top], 16)
VStack {
Multiselect(items: $viewModel.selectableDomains) { domain in
HStack {
if domain.isSelected {
Image(uiImage: #imageLiteral(resourceName: "check-box-active-2-1")).renderingMode(.original)
Text(domain.domain.name)
.foregroundColor(Color.black)
Spacer()
} else {
Image(uiImage: #imageLiteral(resourceName: "check-box-active-1")).renderingMode(.original)
Text(domain.domain.name)
.foregroundColor(Color.orGrayColor)
Spacer()
}
}
}
}.padding([.top, .bottom], 15)
.background(Color.white)
.cornerRadius(8)
Spacer()
OrangeButton(action: {
// self.viewModel.getUserSelectableDomains(userDomains: self.userProfile.domainsOfInterest)
}) {
Text("Save")
}.padding([.leading, .trailing, .top], 30)
.padding(.bottom, 24)
}.padding([.leading, .trailing], 12)
.navigationBarTitle("Domains of interest")
.background(Color.orBackgroundGrayColor.edgesIgnoringSafeArea(.all))
.onAppear {
self.viewModel.getUserSelectableDomains(userDomains: self.userProfile.domainsOfInterest)
}
}
}
//
//struct DomainsOfInterestView_Previews: PreviewProvider {
// static var previews: some View {
// DomainsOfInterestView()
// }
//}
struct Multiselect<T: Selectable, V: View>: View {
@Binding var items: [T]
var rowBuilder: (T) -> V
var body: some View {
ForEach(items.indices,id: \.self) { index in
VStack {
Button(action: { self.items.toggleSelected(self.items[index]) }) {
self.rowBuilder(self.items[index])
}
if index != self.items.count - 1 {
Divider()
}
}.padding([.trailing, .leading], 12)
}
}
}
这是我的viewModel,带有方法getUserSelectableDomains(userDomains:[InterestDomain]),该方法在onAppear()内部调用:
class DomainsViewModel: ObservableObject {
@Published var domains: [InterestDomain] = [InterestDomain]()
@Published var userSelectedDomains: [InterestDomain : Bool] = [InterestDomain : Bool]()
@Published var selectableDomains: [SelectableDomain] = []
init() {
self.getDomains { (response) in
print(response)
}
}
func getUserSelectableDomains( userDomains: [InterestDomain]) {
for domain in domains{
if userDomains.contains(where: { (userDomain) -> Bool in
userDomain.uuid == domain.uuid
})
{
self.selectableDomains.append(SelectableDomain(domain: domain, isSelected: true))
} else {
self.selectableDomains.append(SelectableDomain(domain: domain, isSelected: false))
}
}
}
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(domainsOfInterest != nil)
case .failure(_):
completion(false)
}
}
}
}
viewModel中的selectableDomains var是正在UI上显示的数据源。如果我在按钮而不是onAppear()上调用函数getUserSelectableDomains(userDomains:[InterestDomain]),则它工作正常,UI正在正确更新。如果我在onAppear()内调用它,最初它可以工作,但是不到1秒,此后什么也没显示,就像数据为空。
答案 0 :(得分:0)
@Published
属性需要在主线程上设置-在后台(例如,在异步任务中)更新它们时,请尝试使用DispatchQueue.main
。
func getDomains(completion: @escaping (Bool) -> Void) {
NetworkEngine.shared.appNetwork.getInterestDomains { result in
DispatchQueue.main.async {
self.domains.removeAll()
}
switch result {
case .success(let domainsOfInterest):
if let domainsList = domainsOfInterest {
DispatchQueue.main.async {
self.domains = domainsList
}
}
completion(domainsOfInterest != nil)
case .failure:
completion(false)
}
}
}