Home > Enterprise >  SwiftUI iOS - Bug when using NavigationLink with condition and AppStorage
SwiftUI iOS - Bug when using NavigationLink with condition and AppStorage

Time:06-07

At the beginning I'm declaring:

@AppStorage("userid") var userid: Int = 0

then couple lines of code down below:

if(userid == 0){

    NavigationLink(destination: Login(), label: {
        Image(systemName: "person.circle.fill")
            .resizable()
            .aspectRatio(contentMode: .fit).frame(width: 32)
            .foregroundColor(Color(UIColor(named: "IconColor")!))
    })

}else{
    
    NavigationLink(destination: Profile(), label: {
        AsyncImage(url: URL(string: "https://cdn.icon-icons.com/icons2/2108/PNG/512/stackoverflow_icon_130823.png")) { phase in
            switch phase {
            case .empty:
                Image(systemName: "person.circle.fill")
                    .resizable()
                    .aspectRatio(contentMode: .fit).frame(width: 32)
                    .foregroundColor(Color(UIColor(named: "IconColor")!))
            case .success(let image):
                image.resizable()
                     .aspectRatio(contentMode: .fit)
                     .frame(maxWidth: 32)
            case .failure:
                Image(systemName: "person.circle.fill")
                    .resizable()
                    .aspectRatio(contentMode: .fit).frame(width: 32)
                    .foregroundColor(Color(UIColor(named: "IconColor")!))
            @unknown default:
                Image(systemName: "person.circle.fill")
                    .resizable()
                    .aspectRatio(contentMode: .fit).frame(width: 32)
                    .foregroundColor(Color(UIColor(named: "IconColor")!))
            }
        }
    })
}

Problem 1:

When the userid is 0 and I tap the image to get to Login():

struct Login: View {
    @AppStorage("userid") var userid: Int = 0

    var body: some View{
        
        Button(action: {
            userid = 777
        }) {
            Text("login")
        }
    }
}

to change the AppStorage userid to 777 by clicking on login then Login() view closes which I don't want, the condition in the main view correctly changed to destination: Profile() and shows the downloaded image though.

Problem 2:

When I tap the image to go to Profile():

struct Profile: View {
    @AppStorage("userid") var userid: Int = 0

    var body: some View{
        
        Button(action: {
            userid = 0
        }) {
            Text("profile: logout")
        }
    }
}

to click on logout then the view doesn't close but apparently AppStorage userid doesn't get changed to 0 because the main view still shows the downloaded image and the destination is still Profile().

How to do this correctly?

CodePudding user response:

What I think you need to take a look at is the isActive argument for a NavigationLink that allows you to programmatically show a View. Here are the docs.

What you can do is create a property like hasLoggedIn and pass it to the LoginView and to the NavigationLink for the ProfileView. Check out the code snippet I just wrote, I guess it does what you want.

struct MainView: View {
    @AppStorage("userid") var userId: Int = 0
    @State var hasLoggedIn = false

    var body: some View {
        NavigationView {
            List {
                if (userId == 0) {
                    NavigationLink {
                        LoginView(hasLoggedIn: $hasLoggedIn)
                    } label: {
                        Text("Login")
                    }
                } else {
                    NavigationLink(isActive: $hasLoggedIn) {
                        ProfileView()
                    } label: {
                        Text("Profile")
                    }
                }
            }
        }
    }
}

struct LoginView: View {
    @AppStorage("userid") var userId: Int = 0
    @Binding var hasLoggedIn: Bool

    var body: some View {
        Button {
            userId = 777
            hasLoggedIn = true
        } label: {
            Text("Login")
        }
    }
}

struct ProfileView: View {
    @AppStorage("userid") var userId: Int = 0

    var body: some View {
        Button {
            userId = 0
        } label: {
            Text("Profile")
        }
    }
}

Regarding Problem 2, I didn't face it. Everything worked for you were describing, maybe I misunderstood you.

Oh and definitely take a look at the MVVM pattern as it may be not the best solution to put everything in the Views

  • Related