iosswiftswiftuiuserdefaultsswiftui-environment

New To Swift: Im not sure why the names of the users are not displaying? Swift UI


So I created this project to learn Swift Ui but I am stuck. I can't figure out why the HomeView isn't displaying the name of the contact. I created the ContactModel to store the contact details and the ContactViewModel to store all of the contacts in userDefaults.I stored the information in UserDefaults, but for some reason it just isn't working. I added all my files from the Xcode project. Thanks for the help!

@main
struct ContactsAppApp: App {
    @StateObject var contactViewModel: ContactViewModel = ContactViewModel()
    
    var body: some Scene {
        WindowGroup {
            NavigationView{
                ContentView()
            }
            .environmentObject(contactViewModel)
           
        }
    }
}
    struct ContentView: View {
    var body: some View {
        TabView{
            HomeView()
                .tabItem {
                    Image(systemName: "house")
                        .foregroundColor(.white)
                    Text("home")
                }
            AddContactView()
                .tabItem{
                    Image(systemName: "laptopcomputer")
                    Text("work")
                }
        }
        
    }
}




struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
struct ContactModel: Identifiable, Codable {
let id: String
let name: String
let phoneNumber: String
let email: String

init(id: String = UUID().uuidString, name: String, phoneNumber: String, email: String) {
    self.id = id
    self.name =  name
    self.phoneNumber = phoneNumber
    self.email = email
}

func updateCompletion() -> ContactModel {
    return ContactModel(id: id, name: name, phoneNumber: phoneNumber, email: email)
}

}

class ContactViewModel: ObservableObject {

@Published var items: [ContactModel] = [] {
    didSet {
        saveItems()
    }
}

let itemsKey: String = "items_list"

init() {
    getItems()
}

func getItems() {
    guard
        let data = UserDefaults.standard.data(forKey: itemsKey),
        let savedItems = try? JSONDecoder().decode([ContactModel].self, from: data)
    else { return }

    self.items = savedItems
}

func deleteItem(indexSet: IndexSet) {
    items.remove(atOffsets: indexSet)
}

func moveItem(from: IndexSet, to: Int) {
    items.move(fromOffsets: from, toOffset: to)
}

func addItem(name: String, phoneNumber: String, email: String) {
    let newItem = ContactModel(name: name, phoneNumber: phoneNumber, email: email)
    items.append(newItem)
}

func updateItem(item: ContactModel) {
    if let index = items.firstIndex(where: { $0.id == item.id }) {
        items[index] = item.updateCompletion()
    }
}

func saveItems() {
    if let encodedData = try? JSONEncoder().encode(items) {
        UserDefaults.standard.set(encodedData, forKey: itemsKey)
    }
}

}


import SwiftUI

struct HomeView: View {
    @EnvironmentObject var contactViewModel: ContactViewModel
    
    var body: some View {
        NavigationView {
            VStack {
                HStack{
                    Text("Contacts")
                        .font(.system(size: 35, weight: .bold))
                        .padding(.leading,30)
                        .padding(.top,20)
                        .foregroundColor(.white)
                    Spacer()
                }
                
                Spacer()
                
                ScrollView{
                    
                    ForEach(contactViewModel.items) { item in
                        contactWidget(name: item.name)
                    }
                        
                        
                }
                .padding(.top,20)
                
                Button(action: {
                    print("touched")
                }, label: {
                    NavigationLink(destination: AddContactView().navigationBarBackButtonHidden(true)) {
                        HStack{
                            ZStack{
                            RoundedRectangle(cornerRadius: 40)
                                .frame(width: 200, height: 50)
                                .foregroundColor(.blue)
                            Text("Add Contact")
                                    .foregroundColor(.white)
                            }
                        }
                      
                    }
                    .navigationBarHidden(true)
                })
               
            }
            .background(.black)
        }
        .navigationBarHidden(true)
      
       
    }
}

struct contactWidget : View{
    let name: String
    var body: some View{
        ZStack {
            RoundedRectangle(cornerRadius: 20)
                .frame(width: 350, height: 100)
            .foregroundColor(.gray)
            HStack {
                Image(systemName: "person")
                    .resizable()
                    .clipShape(Circle())
                .frame(width: 40, height: 40)
                Text(name)
                    .font(.system(size: 18, weight: .semibold))
                Spacer()
                HStack{
                    Circle()
                    .frame(width: 40, height: 40)
                    .foregroundColor(.orange)
                    Circle()
                    .frame(width: 40, height: 40)
                    .foregroundColor(.blue)
                    Circle()
                    .frame(width: 40, height: 40)
                    .foregroundColor(.pink)
                }
                
            }
            .padding(.leading,40)
            .padding(.trailing,30)
            
        }
    }
}

struct HomeView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView{
            HomeView()
        }
        .environmentObject(ContactViewModel())
    }
}
import SwiftUI

struct AddContactView: View {
    @EnvironmentObject var contactViewModel: ContactViewModel
    @State var contactName: String = ""
    @State var phoneNumber: String = ""
    @State var email: String = ""
    
    
    var body: some View {
        NavigationView {
            VStack {
                HStack{
                    Text("Contacts")
                        .font(.system(size: 35, weight: .bold))
                        .padding(.leading,30)
                        .padding(.top,20)
                        .foregroundColor(.white)
                    Spacer()
                }
                
                TextField("Enter name", text: $contactName)
                    .frame(width: 330, height: 30)
                    .padding()
                    .background(.white)
                    
                    .cornerRadius(10)
                
                TextField("Enter Phone Number", text: $phoneNumber)
                    .frame(width: 330, height: 30)
                    .padding()
                    .background(.white)
                    
                    .cornerRadius(10)
                
                TextField("Enter Email", text: $email)
                    .frame(width: 330, height: 30)
                    .padding()
                    .background(.white)
                    
                    .cornerRadius(10)
                
                Text(contactName)
                    .foregroundColor(.white)
                    
                
        
                Spacer()
                
                
                .padding(.top,20)
                
                Button(action: {
                    contactViewModel.addItem(name: contactName, phoneNumber: phoneNumber, email: email)
                    
                    contactName = ""
                    phoneNumber = ""
                    email = ""
                    
                }, label: {
                    NavigationLink(destination: HomeView().navigationBarBackButtonHidden(true)) {
                        HStack{
                            ZStack{
                            RoundedRectangle(cornerRadius: 40)
                                .frame(width: 200, height: 50)
                                .foregroundColor(.blue)
                            Text("Done")
                                    .foregroundColor(.white)
                            }
                        }
                      
                    }
                    .navigationBarHidden(true)
                })
               
            }
            .background(.black)
        }
        .navigationBarHidden(true)
      
       
    }
}



struct AddContactView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView{
            AddContactView()
        }
        .environmentObject(ContactViewModel())
    }
}

Solution

  • The reason "...why the HomeView isn't displaying the name of the contact..." is because you have NavigationLink(destination: HomeView().... inside the button label in AddContactView. That is, the tap is caught by the NavigationLink and goes to the HomeView without doing the button action of adding the contact, contactViewModel.addItem( ...). So restructure your code with the NavigationLink outside of it.

    The example code below should fix your problem.

    struct AddContactView: View {
        @EnvironmentObject var contactViewModel: ContactViewModel
        @State var contactName: String = ""
        @State var phoneNumber: String = ""
        @State var email: String = ""
        
        @State var goHome = false  // <-- here
        
        var body: some View {
            NavigationView {
                VStack {
                    HStack{
                        Text("Contacts")
                            .font(.system(size: 35, weight: .bold))
                            .padding(.leading,30)
                            .padding(.top,20)
                            .foregroundColor(.white)
                        Spacer()
                    }
                    TextField("Enter name", text: $contactName)
                        .frame(width: 330, height: 30)
                        .padding()
                        .background(.white)
                        .cornerRadius(10)
                    
                    TextField("Enter Phone Number", text: $phoneNumber)
                        .frame(width: 330, height: 30)
                        .padding()
                        .background(.white)
                        .cornerRadius(10)
                    
                    TextField("Enter Email", text: $email)
                        .frame(width: 330, height: 30)
                        .padding()
                        .background(.white)
                        .cornerRadius(10)
                    
                    Text(contactName).foregroundColor(.white)
                    
                    Spacer().padding(.top,20)
                    
                    Button(action: {
                        contactViewModel.addItem(name: contactName, phoneNumber: phoneNumber, email: email)
                        
                        contactName = ""
                        phoneNumber = ""
                        email = ""
                        
                        goHome = true  // <-- here
                    }, label: {
                        HStack{
                            ZStack{
                                RoundedRectangle(cornerRadius: 40)
                                    .frame(width: 200, height: 50)
                                    .foregroundColor(.blue)
                                Text("Done")
                                    .foregroundColor(.white)
                            }
                        }
                    })
                    
                    // -- here
                    NavigationLink(destination: HomeView().navigationBarBackButtonHidden(true), isActive: $goHome) {
                        EmptyView()
                    }.navigationBarHidden(true)
                    
                }
                .background(.black)
            }
            .navigationBarHidden(true)
        }
    }
    

    Similarly for the button in HomeView, or remove the Button part, just keep the NavigationLink