Home > Blockchain >  Get object at the start of view swiftui
Get object at the start of view swiftui

Time:11-11

I have a view and I want to load the data from the database from the start of the view, because I want to edit the profile of my user.
So whenever I will start the my view, the data will be loaded. This is my code but it gives me an exception on the TextField.

struct ProfileView: View {
    @State var  myUser = User()
    var repo = myRepo()

     var body: some View {
        VStack{
            Form{
                Section(header: Text("edit the name")){
                    TextField("Nume produs", text: self.myUser.name) //IT DOES NOT WORK HERE
                }
            }
        }.onAppear(){
            getMyUser()    
        }

    func getMyUser(){
        Task{
            do{
                try await repo.getUserProfile().watch(block: {item in
                    self.myUser = item as! User
                })
            }catch{
                print("error")
            }
        }
    }
}

This just does not work when I put as a TextField What is the best way to have the data of my object (myUser) right away on the start of the view?

CodePudding user response:

You can show a ProgressView in the interim.

struct ProfileView: View {
    //mimic user, make variable optional until value is received
    @State var  myUser : String?
    //var repo = myRepo() //No code provided

    var body: some View {
        //Check the optional, if a value is available show Custom View
        if let m = Binding($myUser){
            VStack{
                Form{
                    Section(header: Text("edit the name")){
                        TextField("Nume produs", text: m) //use `m.name` in your code
                    }
                }
            }
        }else{ //else show progress view, and fetch the user
            ProgressView()
                .onAppear(){
                    getMyUser()
                }
        }
    }
    func getMyUser(){
        Task{
            do{
                //To mimic delay replace with your code 
                try await Task.sleep(for: .seconds(2))
                //The code you have here is not async await, closures do not work well with async await, it could be the source of your issues.

//                try await repo.getUserProfile().watch(block: {item in
//                    self.myUser = item as! User
//                })
                myUser = "test" //mimic
            }catch{
                print(error)
            }
        }
    }
}

CodePudding user response:

Just init the String as empty and create the @Binding like so:

import SwiftUI

    struct ProfileView: View {
        @State var  myUser = ""
        
        var body: some View {
            VStack{
                Form{
                    Section(header: Text("edit the name")){
                        TextField("Nume produs", text: $myUser) //IT DOES NOT WORK HERE
                    }
                }
            }.onAppear(){
                getMyUser()
            }
        }
        
        func getMyUser() {
            Task{
                do{
                    try await Task.sleep(nanoseconds: 3_000_000_000)
                    
                    myUser = "HELLO"
                }catch{
                    print("error")
                }
            }
        }
    }

enter image description here

CodePudding user response:

If you need the data to be there when the view appears, you could load the data when a button is tapped on the previous screen and you could navigate to the details screen once the data is loaded.

Note: this example uses a depreciated NavigationLink initializer, you could use navigation stacks instead if you’re targeting iOS 16

class Model: ObservableObject {
    var repo = myRepo()
    @Published var user: User? = nil
    @Published bar shouldShowUserView = false

    init() {
        $user
            .map { $0 != nil }
            .assign(to: &$shouldShowUserView)
    }
    
    func fetchUser() {
        Task{
            do {
                try await repo.getUserProfile().watch(block: { item in
                    self.myUser = item as! User
                })
            } catch {
                     print("error")
            }
        }
    }

    func reset() {
        user = nil
    }
}

struct ProfileView: View {
    @EnvironmentObject var model: Model

     var body: some View {
        VStack{
            Form {
                Section(header: Text("edit the name")){
                    TextField("Nume produs", text: $model.myUser.name) //IT DOES NOT WORK HERE
                }
            }
        }
        .onDisappear(perform: model.reset)
    }
}

struct PreviousView: View {
    @EnvironmentObject var model: Model
   
    var body: some View {
        ZStack {
            NavigationLink(destination: { ProfileView() }, isActive: $model.shouldShowUserView, label: { EmptyView() })
            Button(action: {
                model.fetchUser()
            }, label: {
                Text(“Show user details”)
            })
        }
    }
}


  • Related