When modifying the Image color through "onTapGesture", XCode will crash

Hi I am a beginner and I am preparing to make a Tabbar component for use in my practice APP. The component uses Image as the button. When the button is clicked (onTapGesture), I hope that the color in the IMAGE will change, but now When running to onTapGesture, XCode crashes, who knows how to write this code to make it run normally. Thanks



class MainViewManager : ObservableObject{
    @Published var tabbarStatus : TabbarStatus = .homeView
    

    enum TabbarStatus : CaseIterable {
        case homeView
        case articsPage
        case profile
        

        var icon : String{
            switch self{
                
            case .homeView:
                return "house"
            case .articsPage:
                return "person.2"
            case .profile:
                return "person.crop.circle"
            }
        }
    }
}

struct MainTabbar: View {
    @EnvironmentObject var vm : MainViewManager
    @State var btnColor : Color = .gray
    
    var body: some View {

        HStack{

            ForEach(MainViewManager.TabbarStatus.allCases, id: \.self) { tabbarItem in
                
                //let selected = tabbarItem == vm.tabbarStatus
                
                Image(systemName:tabbarItem.icon)
                    .foregroundStyle(btnColor)
                    .onTapGesture {
                        vm.tabbarStatus = tabbarItem 
                        btnColor = Color.accentColor
                    }
                

                if tabbarItem != .profile {
                    Spacer()
                }
                
                
                
                
            }
            
            
        }
        .padding(.horizontal,30)
        .padding(.all)
        .frame(maxHeight: .infinity ,alignment: .bottom)
            .background(Color.white)
           
    }
}

#Preview {
    MainTabbar()
}
Answered by darkpaw in 773118022

I've added a selected tab bar item as a @State var. Such vars should be private because they should only be modified within their own View.

Also, you only really need to change the selection within the .onTapGesture because the view will take its data from the change you made, i.e. the image color is set by the value of selected.

class MainViewManager: ObservableObject{
	@Published var tabbarStatus: TabbarStatus = .homeView

	enum TabbarStatus: CaseIterable {
		case homeView
		case articsPage
		case profile

		var icon: String {
			switch self {
				case .homeView:
					return "house"
				case .articsPage:
					return "person.2"
				case .profile:
					return "person.crop.circle"
			}
		}
	}
}


struct MainTabbar: View {
	@EnvironmentObject var vm: MainViewManager
	@State private var selected: MainViewManager.TabbarStatus = .homeView

	var body: some View {
		HStack {
			ForEach(MainViewManager.TabbarStatus.allCases, id: \.self) { tabbarItem in
				Image(systemName: tabbarItem.icon)
					.foregroundStyle(tabbarItem == selected ? Color.accentColor : .gray)
					.onTapGesture {
						selected = tabbarItem
					}

				if(tabbarItem != .profile) {
					Spacer()
				}
			}
		}
		.padding(.horizontal, 30)
		.padding(.all)
		.frame(maxHeight: .infinity, alignment: .bottom)
		.background(Color.white)
	}
}


#Preview {
	MainTabbar()
}
Accepted Answer

I've added a selected tab bar item as a @State var. Such vars should be private because they should only be modified within their own View.

Also, you only really need to change the selection within the .onTapGesture because the view will take its data from the change you made, i.e. the image color is set by the value of selected.

class MainViewManager: ObservableObject{
	@Published var tabbarStatus: TabbarStatus = .homeView

	enum TabbarStatus: CaseIterable {
		case homeView
		case articsPage
		case profile

		var icon: String {
			switch self {
				case .homeView:
					return "house"
				case .articsPage:
					return "person.2"
				case .profile:
					return "person.crop.circle"
			}
		}
	}
}


struct MainTabbar: View {
	@EnvironmentObject var vm: MainViewManager
	@State private var selected: MainViewManager.TabbarStatus = .homeView

	var body: some View {
		HStack {
			ForEach(MainViewManager.TabbarStatus.allCases, id: \.self) { tabbarItem in
				Image(systemName: tabbarItem.icon)
					.foregroundStyle(tabbarItem == selected ? Color.accentColor : .gray)
					.onTapGesture {
						selected = tabbarItem
					}

				if(tabbarItem != .profile) {
					Spacer()
				}
			}
		}
		.padding(.horizontal, 30)
		.padding(.all)
		.frame(maxHeight: .infinity, alignment: .bottom)
		.background(Color.white)
	}
}


#Preview {
	MainTabbar()
}

Thanks. i will try it

When modifying the Image color through "onTapGesture", XCode will crash
 
 
Q