NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

@State property wrapper not working in FlagImage Struct

Forums > SwiftUI

When I try using an @State property wrapper in my first struct, FlagImage, it doesn't work. Xcode gives me this error: "'FlagImage' initializer is inaccessible due to 'private' protection level" - Why is it doing this? I don't really understand the error.

I took @State off and it works just fine. Below is my code of the app that works without the property wrapper

import SwiftUI

struct FlagImage: View {
    var flag: String

    var body: some View {
        Image(flag)
            .renderingMode(.original)
            .clipShape(Capsule())
            .shadow(radius: 8)
    }
}

struct Title: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.largeTitle)
            .foregroundColor(.accentColor)
            .padding()
    }
}

extension View {
    func titleStyle() -> some View {
        modifier(Title())
    }
}

struct ContentView: View {

    @State private var showingScore = false
    @State private var scoreTitle = ""
    @State private var userScore = 0
    @State private var maxNumberOfQuestions = 8

    @State private var questionTitle = ""
    @State private var endGame = false
    @State private var currentQuestion = 1
    @State private var correctAnswer = Int.random(in: 0...2)

    @State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled()

    var body: some View {
        ZStack {

            RadialGradient(gradient: Gradient(colors: [Color("Light Pink"), Color("Light Blue")]), center: .bottom, startRadius: 200, endRadius: 400)
                .ignoresSafeArea()

            VStack {

                Spacer()

                HStack {

                    Image(systemName: "flag.filled.and.flag.crossed").foregroundColor(.black)
                    Text("Guess the Flag")
                        .titleStyle()
                    Image(systemName: "flag.and.flag.filled.crossed").foregroundColor(.black)
                }

                VStack(spacing: 15) {

                    Text("Tap the flag of")
                        .foregroundStyle(.secondary)
                        .font(.subheadline.weight(.heavy))
                    Text(countries [correctAnswer]).font(.largeTitle.weight(.semibold))

                    ForEach(0..<3) { number in
                        Button {
                            print("tapped \(countries[number])")
                            flagTapped(number)

                        } label: {
                            FlagImage(flag: countries[number])
                        }
                    }
                }
                .frame(maxWidth:350)
                .padding(.vertical, 20)
                .background(.thinMaterial)
                .clipShape(RoundedRectangle(cornerRadius: 100))

                Spacer()
                Spacer()

                Text("Score: \(userScore)")
                    .foregroundColor(.black)
                    .font(.title.bold())
                Text("Question: \(currentQuestion)")
                    .foregroundColor(.black)
                    .font(.title.bold())

                Spacer()
            }
            .padding()
        }
        .alert(questionTitle, isPresented: $endGame) {
            Button("RESTART GAME", action: newGame)
        } message: {
            Text("Congrats! Final Score: \(userScore).")
        }
        .alert(scoreTitle, isPresented: $showingScore) {
            Button("Continue", action: askQuestion)
        } message: {
            Text("Your Score: \(userScore).")
        }
    }
    func flagTapped(_ number: Int) {
        if number == correctAnswer {
            scoreTitle = "Correct"
            userScore += 10
        } else {
            scoreTitle = "Wrong! It's the flag of \(countries[correctAnswer])."
        }
        showingScore.toggle()
    }
    func askQuestion() {
        if currentQuestion < 8 {
            countries.shuffle()
            currentQuestion += 1
            correctAnswer = Int.random(in: 0...2)
        } else {
            endGame.toggle()
        }
    }
    func newGame() {
        if currentQuestion == 8 {
            userScore = 0
            currentQuestion = 0
            countries.shuffle()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

   

I ran your project by copy and pasting to a new project and got no errors!

   

As @NigelGee says, your code works. As a general rule, when asking for help you should post the non-working code for people to play around with.

Anyway, presumably your non-working code had something like this:

@State private var flag: String

That would make this line:

FlagImage(flag: countries[number])

have the exact error you reference in your post. That's because flag is marked as private.

You can fix the error by adding an initializer to FlagImage like so:

    init(flag: String) {
        self._flag = State(wrappedValue: flag)
        //this initializes the @State property wrapper with the passed-in value
    }

But as you've found, you can also fix that error by removing the @State private part. In this case, @State is not actually necessary since you don't make any changes to flag inside the FlagImage struct. @State is used when you need to change a property of a View; if you aren't changing a property, it doesn't need to be marked as @State.

   

Hacking with Swift is sponsored by MadMachine

SPONSORED Want to try Swift on microcontrollers? MadMachine provides ways to interact with the physical world in a Swift way. Join us and have fun!

Get it now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.