Adding the code first to help better understand the problem.
struct MainSetupView: View {
@StateObject var viewModel: MainViewModel
var body: some View {
VStack {
switch viewModel.state {
case .idle:
Color.clear.onAppear(perform: { viewModel.prepare() })
case .loading:
ProgressView()
case .showMessage(let messageType, let messageText):
ErrorHandlingView(messageType: messageType, messageText: messageText)
}
}.onAppear() {
viewModel.state = .idle
}
}
}
struct ErrorHandlingView: View {
@State var messageType: String
var messageText: String
@State private var messageViewImageDetails: (imageName: String, isSystemImage: Bool) = (imageName: "", isSystemImage: false)
var body: some View {
VStack {
MessageViewWithActions(imageName: messageViewImageDetails.imageName, isSystemImage: messageViewImageDetails.isSystemImage, mainMessageText: messageText)
}.onChange(of: messageType) {_ in
self.messageViewImageDetails = getImageForError()
// call more functions
}
}
private func getImageForError() -> (imageName: String, isSystemImage: Bool) {
var imageName = ""
var isSystemImage = false
switch messageType {
case "noInternetError":
imageName = "xmark.icloud"
isSystemImage = true
case "userSignedOut":
imageName = "person.crop.circle.fill.badge.xmark"
isSystemImage = true
case "userSignedIn":
imageName = "person.crop.circle.badge.checkmark"
isSystemImage = true
// more cases.
default:
imageName = "info.circle"
isSystemImage = true
}
return (imageName: imageName, isSystemImage: isSystemImage)
}
}
If "MainSetupView" is open and I receive a message ie .showMessage, "ErrorHandlingView" is displayed and I set "messageType" and "messageText" while calling ErrorHandlingView. While first message is being displayed, let's say I receive another message and "ErrorHandlingView" gets called again, now with a different message type. However "onChange(of: messageType)" in "ErrorHandlingView" never gets called.
"onChange(of: messageType)" calls a function "getImageForError" which tells the app which image to display based on the value of messageType. Since code in onChange is not getting executed, "getImageForError" never gets called and hence "messageViewImageDetails" is never populated which results in view without image.
Any idea why is.onChange() not being executed? What am I doing wrong?
Note: I have lots of code and I am sharing pieces of code which I thought would be helpful. Let me know if more code is needed.
Edit : Adding code for MessageViewWithActions.
struct MessageViewWithActions: View {
// Image properties
var imageName: String?
var isSystemImage: Bool = false
// Text properties
var mainMessageText: String?
var body: some View {
ScrollView {
VStack {
Text("")
VStack {
if let imageName = imageName {
if isSystemImage {
Image(systemName: imageName)
} else {
Image(imageName)
}
}
}.frame(maxWidth: .infinity).padding(.bottom, 8)
if let mainMessageText = mainMessageText {
Text(mainMessageText).font(.subheadline).fixedSize(horizontal: false, vertical: true)
}
}
}
}
}
Changing messageType to Binding var instead of State var worked. Sharing updated code for future:
struct MainSetupView: View {
@StateObject var viewModel: MainViewModel
@State var messageType: String
var body: some View {
VStack {
switch viewModel.state {
case .idle:
Color.clear.onAppear(perform: { viewModel.prepare() })
case .loading:
ProgressView()
case .showMessage(_, let messageText):
ErrorHandlingView(messageType: messageType, messageText: messageText)
}
}.onAppear() {
viewModel.state = .idle
}.onReceive(viewModel.$state, perform: { (value) in
switch value {
case .showMessage(let messageType, _):
self.messageType = messageType
case .idle, .loading:
print("")
}
})
}
}
struct ErrorHandlingView: View {
@Binding var messageType: String
var messageText: String
@State private var messageViewImageDetails: (imageName: String, isSystemImage: Bool) = (imageName: "", isSystemImage: false)
var body: some View {
VStack {
MessageViewWithActions(imageName: messageViewImageDetails.imageName, isSystemImage: messageViewImageDetails.isSystemImage, mainMessageText: messageText)
}.onChange(of: messageType) {_ in
self.messageViewImageDetails = getImageForError()
// call more functions
}
}
private func getImageForError() -> (imageName: String, isSystemImage: Bool) {
var imageName = ""
var isSystemImage = false
switch messageType {
case "noInternetError":
imageName = "xmark.icloud"
isSystemImage = true
case "userSignedOut":
imageName = "person.crop.circle.fill.badge.xmark"
isSystemImage = true
case "userSignedIn":
imageName = "person.crop.circle.badge.checkmark"
isSystemImage = true
// more cases.
default:
imageName = "info.circle"
isSystemImage = true
}
return (imageName: imageName, isSystemImage: isSystemImage)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.