I use combine to connect to a REST API which pulls some data into an ObservableObject. The whole setup is really just MVVM. The ObservableObject is then being Observed in a view. Now, I'm stuck with a bug I can't seem to get resolved. What seems to happen is that the View is drawn twice. The first time it updates with the values from the ObservedObject. Then it immediately re-draws, but now the pulled data is suddenly gone. I have confirmed that the code that pulls the data is not executed a second time. Also, the View Hierarchy Viewer seems to suggest that the Text Views which are supposed to be render the data in the view are somehow deleted on the second render run.
This is what the model looks like (the authentication related code is from Firebase):
class ItemViewModel: ObservableObject {
@Published var items = [ScheduleItem]()
private var publisher: AnyCancellable?
func fetchData() {
let currentUser = Auth.auth().currentUser
currentUser?.getIDTokenForcingRefresh(false, completion: { idToken, error in
let url = URL(string: "abc")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Bearer "+String(idToken!), forHTTPHeaderField: "Authorization")
self.publisher = URLSession.shared
.dataTaskPublisher(for: url)
.map(.data)
.decode(
type: [ScheduleItem].self,
decoder: JSONDecoder()
)
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { completion in
switch completion {
case .failure(let error):
print("SINKERROR")
print(error)
case .finished:
print("SINKSUCCESS")
}
},
receiveValue: { repo in
print("DONE")
self.items.append(contentsOf: repo)
}
)
})
}
}
The output from the print statements is
DONE
SINKSUCCESS
Both can only be found once in the debug output.
This is the view:
struct TreatmentCardView: View {
let startDate: String
let uid: Int
@ObservedObject var data = ItemViewModel()
@State private var lastTime: String = "2"
var body: some View {
ZStack {
GeometryReader { geometry in
VStack{
Text("Headline")
.font(.title)
.foregroundColor(Color.white)
.padding([.top, .leading, .bottom])
Print("ISARRAYEMPTY")
Print(String(data.items.isEmpty))
Text(String(data.items.isEmpty))
.font(.headline)
.fontWeight(.light)
.foregroundColor(Color.white)
.frame(width: 300, height: 25, alignment: .leading)
.multilineTextAlignment(.leading)
.padding(.top)
}
}
}
.background(Color("ColorPrimary"))
.cornerRadius(15)
.onAppear{
self.data.fetchData()
}
}
}
Print(String(data.items.isEmpty)) is first false, then true, indicating the view was re-rendered.
What is a bit weird to me is that I would have expected the view to render at least once before the data is pulled, but I don't see any indication of this happening.
I've been trying to make this word for two days now. Any help and advise is greatly appreciated!
question from:
https://stackoverflow.com/questions/65925048/data-from-observedobject-not-rendered-in-swiftui-view 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…