swiftswiftui

Variable not refreshing after making a selection on a sheet


Me again with what is probably another stupid mistake. The issue at the moment is this. I am using Apple's MKLocalSearchCompleter to get the name and address for a restaurant. I am also using SwiftData to store everything. I have a sheet being presented over the form. Before calling the sheet the varsity show the correct placeholder text. In this case "tacos" for the restaurant name and "bell" for the address. Once you click the location button, you can search and tap on the one you want. The on tap is updating the review.resataurantName and review.location because i have it printing them to the console. However it will not update them values in the form. Here's my code that i think is relevant to the issue.

Here is the edit meal view

import SwiftUI
import PhotosUI
import SwiftData


struct EditMealView: View {
    @Binding var isPresentingNewMealView: Bool
    @Environment(\.modelContext) private var modelContext
    @State var mealImage: Image? = nil
    @State private var selectedItem: PhotosPickerItem? = nil
    @Bindable var review: Review
    @State private var imageData: Data?
    @State var selection: TextSelection? = nil
    @State private var locationService = LocationService(completer: .init())
    @State private var search: String = ""
    @State private var isPresentingLocationView = false
    
    // @State var chosenLocation: String? = AddressView($locationSubtitle)
    
    let foodTypeList: [String] = ["Select One...", "Fast Food", "Vegetarian", "Central African", "East African", "North African", "Southern Africa", "West African", "Latin American", "Native American", "Canadian", "Carribean", "Mexican", "American", "Southern American", "Fusion", "Central American", "South American", "Chinese", "Japanese", "Korean", "Indian", "Middle Eastern", "Thai", "Turkish", "Vietnamese", "Italian", "French", "German", "Spanish", "Greek", "Romanian", "Russian", "Eastern European", "Scandinavian", "British", "Dutch", "Swedish", "Norwegian", "Icelandic", "Irish", "Polynesian", "Australian", "New Zealand", "Other"]
    
    var body: some View {
        NavigationStack {
            ZStack {
                LinearGradient(gradient: Gradient(colors: [Color(red: 0.9725490196078431, green: 0.9607843137254902, blue: 0.8627450980392157, opacity: 1), Color(red: 0.9137254901960784, green: 0.9254901960784314, blue: 0.8509803921568627, opacity: 1), Color(red: 0.9882352941176471, green: 0.7529411764705882, blue: 0.13333333333333333, opacity: 1), Color(red: 0.9450980392156862, green: 0.47058823529411764, blue: 0.08627450980392157, opacity: 1)]), startPoint: .top, endPoint: .bottom).ignoresSafeArea()
                
                    .navigationTitle("Add Meal")
                
                VStack{
                    Form {
                        
                        TextField("Menu Item", text: $review.foodName)
                            .listRowBackground(Color.clear)
                            .autocorrectionDisabled()
                        
                        HStack {
                            Button(action: {isPresentingLocationView = true}
                            ) {
                                Text("Location")
                                Image(systemName: "map")
                            }
                            
                            .sheet(isPresented: $isPresentingLocationView) {
                                AddressView(isPresentingLocationView: $isPresentingLocationView, review: Review(foodName: "", restaurantName: "", location: "muncie", rating: 3, foodImage: nil, foodType: "", reviewNotes: "")//,  //restaurantName: ""
                                )
                            }
                            VStack {
                                Text("\(review.restaurantName)")
                                    .listRowBackground(Color.clear)
                                    .autocorrectionDisabled()
                                Text("\(review.location)")
                                    .listRowBackground(Color.clear)
                                    .autocorrectionDisabled()
                            }
                            
                        }
                        .listRowBackground(Color.clear)
                        Picker(selection: $review.foodType, label: Text("\(review.foodType)")) {
                            ForEach(0..<foodTypeList.count, id: \.self) {
                                Text(self.foodTypeList[$0])
                                    .tag(self.foodTypeList[$0])
                            }
                            
                        }
                        .listRowBackground(Color.clear)
                        
                        HStack{
                            Spacer()
                            RatingView(rating: $review.rating)
                                .multilineTextAlignment(TextAlignment.center)
                            Spacer()
                        }
                        .buttonStyle(.plain)
                        .listRowBackground(Color.clear)
                        
                        if let imageData = review.foodImage, let uiImage = UIImage(data: imageData) {
                            Image(uiImage: uiImage)
                                .resizable()
                                .scaledToFit()
                        }
                        PhotosPicker(selection: $selectedItem, matching: .images) {
                            Label("Select a photo", systemImage: "fork.knife")
                        }
                        .onChange(of: selectedItem, loadPhoto)
                        
                        .listRowBackground(Color.clear)
                        .padding()
                    }
                    .listRowBackground(Color.clear)
                    .padding()
                    Spacer()
                    HStack {
                        Text("Notes")
                            .padding()
                            .font(.headline)
                        Spacer()
                    }
                    TextEditor(text: $review.reviewNotes, selection: $selection)
                        .background(Color.white.opacity(0.40))
                }
                .scrollDismissesKeyboard(.immediately)
            }
            
            .scrollContentBackground(.hidden)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Dismiss") {
                        isPresentingNewMealView = false
                    }
                }
                ToolbarItem(placement: .confirmationAction) {
                    Button("Add") {
                        let newReview = review
                        modelContext.insert(newReview)
                        isPresentingNewMealView = false
                        
                    }
                }
            }
            
        }
    }
    func loadPhoto() {
        Task { @MainActor in
            review.foodImage = try await selectedItem?.loadTransferable(type: Data.self)
        }
    }
    
}

the address view

import SwiftUI
import MapKit
import SwiftData

struct AddressView: View {
    @State private var locationService = LocationService(completer: .init())
    @State private var search: String = ""
    @Binding var isPresentingLocationView: Bool
    @Bindable var review: Review
    
    var body: some View {
        NavigationStack {
            ZStack {
                LinearGradient(gradient: Gradient(colors: [Color(red: 0.9725490196078431, green: 0.9607843137254902, blue: 0.8627450980392157, opacity: 1), Color(red: 0.9137254901960784, green: 0.9254901960784314, blue: 0.8509803921568627, opacity: 1), Color(red: 0.9882352941176471, green: 0.7529411764705882, blue: 0.13333333333333333, opacity: 1), Color(red: 0.9450980392156862, green: 0.47058823529411764, blue: 0.08627450980392157, opacity: 1)]), startPoint: .top, endPoint: .bottom).ignoresSafeArea()
                
                    .navigationTitle("Add Location")
                
                VStack {
                    HStack {
                        Image(systemName: "magnifyingglass")
                        TextField("Search for a restaurant", text: $search)
                            .autocorrectionDisabled()
                    }
                    
                    Spacer()
                    
                    List {
                        ForEach(locationService.completions) { completion in
                            Button(action: {didTapOnCompletion(completion)}) {
                                VStack(alignment: .leading, spacing: 4) {
                                    Text(completion.title)
                                        .font(.headline)
                                        .fontDesign(.rounded)
                                    Text(completion.subTitle)
                                }
                            }
                            
                            .listRowBackground(Color.clear)
                        }
                    }
                    .listStyle(.plain)
                    .scrollContentBackground(.hidden)
                }
                .onChange(of: search) {
                    locationService.update(queryFragment: search)
                }
                .padding()

                .presentationBackground(.regularMaterial)
                .presentationBackgroundInteraction(.enabled(upThrough: .large))
            }
        }
    }
    private func didTapOnCompletion(_ completion: SearchCompletions) {
        isPresentingLocationView = false
        review.restaurantName = completion.title
        review.location = completion.subTitle
        print("this is the name \(review.restaurantName) and this is the location \(review.location)")

    }
}

I can not figure out what is going on. Here is a little gif as well. enter image description here


Solution

  • You should pass the review property to the AddressView instead of creating and passing a new instance of Review