iosswiftswiftui

SwiftUI, Image View not matching with selected enum case details


In this mobile Rock, Paper, Scissors game I'm developing, I expect to have specific Image and Text Views populate to represent the user's and computer's move. So far, the correct Image and Text View appears for the user but not for the computer. The logic is sound, as I've used multiple print statements to check to see if the details for a randomly selected enum case are all the same but for some reason, the Image and Text View differ from the computer's move. I'm too new to really understand what is going on, can anyone offer an explanation so that I can come up with a solution? Please let me know if more information is needed.

struct PlayerVSComputerView: View {
    var randomRawValue = Int.random(in: 0...2)    
    var body: some View {
        NavigationView{
            ZStack{
                VStack{
                    let computerChoice = MoveOptionModel(rawValue: randomRawValue)!
                
                    MoveOptionIcon(moveImage: computerChoice.id.iconImage, moveTitle: computerChoice.id.iconTitle)
                
                    HStack{
                         // other Views
                    }// HStack End
                    .onAppear {
                         print("Raw Value: \(randomRawValue), Computer Choice: \(computerChoice), Icon Title: \(computerChoice.id.iconTitle), ID: \(computerChoice.id)")
                    }
                }// VStack End
            }// ZStack End
        }// NavigationView End
    }// body End
}


enum MoveOptionModel: Int, CaseIterable, Identifiable {
    case rock = 0
    case paper = 1
    case scissors = 2

    var id: MoveOptionModel { self }

    var iconImage: ImageResource {
        switch self {
        case .rock:
                .rock
        case .paper:
                .paper
        case .scissors:
                .scissors
        }
    }

    var iconTitle: String {
        switch self {
        case .rock:
            "Rock"
        case .paper:
            "Paper"
        case .scissors:
            "Scissors"
        }
    }
}

struct MoveOptionIcon: View {
    let moveImage: ImageResource
    let moveTitle: String

    var body: some View {
        VStack{
            Image(moveImage)
                .resizable()
                .scaledToFit()
                .frame(height: 100)
        
            Text(moveTitle)
                .font(.title)
                .italic()
                .foregroundStyle(.black)
            
        }
        .padding(10)
    }
}

Solution

  • The solution is to turn randomValue into a State property. I also created a button to run again the random assignment. I am not sure why you need it to be identifiable, but in this case, I removed the protocol and id.

    struct PlayerVSComputerView: View {
        @State var randomRawValue = Int.random(in: 0...2)
        var body: some View {
            NavigationView{
                ZStack{
                    VStack{
                        let computerChoice = MoveOptionModel(rawValue: randomRawValue)!
    
                        MoveOptionIcon(moveImage: computerChoice.iconImage, moveTitle: computerChoice.iconTitle)
    
                        Button("Play Again") {
                            var newRandomRawValue = Int.random(in: 0...2)
                            while newRandomRawValue == randomRawValue {
                                newRandomRawValue = Int.random(in: 0...2)
                                // Ensure the new random value is different from the previous one
                            }
                            randomRawValue = newRandomRawValue
                        }
                        .onAppear {
                             print("Raw Value: \(randomRawValue), Computer Choice: \(computerChoice), Icon Title: \(computerChoice.iconTitle), Case: \(computerChoice)")
                        }
                    }// VStack End
                }// ZStack End
            }// NavigationView End
        }// body End
    }
    
    
    enum MoveOptionModel: Int, CaseIterable {
        case rock = 0
        case paper = 1
        case scissors = 2
    
        var iconImage: ImageResource {
            switch self {
            case .rock:
                    .rock
            case .paper:
                    .paper
            case .scissors:
                    .scissors
            }
        }
    
        var iconTitle: String {
            switch self {
            case .rock:
                "Rock"
            case .paper:
                "Paper"
            case .scissors:
                "Scissors"
            }
        }
    }
    
    struct MoveOptionIcon: View {
        let moveImage: ImageResource
        let moveTitle: String
    
        var body: some View {
            VStack{
                Image(moveImage)
                    .resizable()
                    .scaledToFit()
                    .frame(height: 100)
    
                Text(moveTitle)
                    .font(.title)
                    .italic()
                    .foregroundStyle(.black)
    
            }
            .padding(10)
        }
    }