0

I have a DB of restaurants in Firestore and I'm trying to query and return a list of 4 items from the restaurant collection. Currently my query is:

import SwiftUI
import Firebase
import SDWebImageSwiftUI

struct ExploreView: View {

    @State var selectedTab = "Explore"
    @State var data: [RestaurantObject] = []
    @State var metro = "Orlando"

let db = Firestore.firestore()

var body: some View {
    NavigationView {
        ScrollView(.vertical, showsIndicators: false) {
            VStack {
                HStack {
                    Text("Explore Orlando")
                        .font(.title)
                        .fontWeight(.bold)
                        
                    Spacer()
                    NavigationLink (destination: LocationsView()) {
                        Text ("Change")
                            .font(.callout)
                    }
                }.padding(.horizontal)
                .padding(.bottom, 30)
                // Cuisine Slider
                HStack {
                    Text("All cuisines")
                        .font(.title2)
                        .fontWeight(.bold)
                    Spacer()
                    NavigationLink (destination: CuisinesView()) {
                        Text("View all")
                    }
                }.padding(.horizontal)
                .padding(.bottom, 20)
                ScrollView (.horizontal, showsIndicators: false) {
                    HStack(spacing: 12.0)  {
                        CuisineTile(image: "cuisine_breakfast", name: "Brunch")
                        CuisineTile(image: "cuisine_bbq", name: "BBQ")
                        CuisineTile(image: "cuisine_brazilian", name: "Brazilian")
                        CuisineTile(image: "cuisine_caribbean", name: "Caribbean")
                        CuisineTile(image: "cuisine_cuban", name: "Cuban")
                        CuisineTile(image: "cuisine_mexican", name: "Mexican")
                        CuisineTile(image: "cuisine_seafood", name: "Seafood")
                        CuisineTile(image: "cuisine_soulfood", name: "Soul Food")
                            .padding(.trailing, 31)
                    }.offset(x: 16)
                }
                // Featured Section
                VStack {
                    HStack {
                        Text("Featured Eats")
                            .font(.title2)
                            .fontWeight(.bold)
                            .foregroundColor(Color.white)
                        Spacer()
                    }.padding(.horizontal)
                    .padding(.top)
                    HStack {
                        Text("Join us every month as we highlight business owners with uplifting and inspiring stories.")
                            .foregroundColor(Color.white)
                            .font(.subheadline)
                        Spacer()
                    }.padding(.horizontal)
                    .padding(.vertical, 5)
                    ZStack {
                        VStack {
                            HStack {
                                Image("placeholder_feature")
                                    .resizable()
                            }.padding(.horizontal)
                        }
                        VStack {
                            Spacer()
                            HStack {
                                Text ("The story behind Papa Llama. Orlando's newest Peruvian restaurant.")
                                    .font(.body)
                                    .foregroundColor(Color.white)
                                    .padding()
                                Spacer()
                            }.background(Color("CharcoalGray"))
                            .cornerRadius(10, corners: [.bottomLeft, .bottomRight])
                            .padding(.horizontal)
                        }
                        
                    }
                    HStack {
                        Button(action: /*@START_MENU_TOKEN@*//*@PLACEHOLDER=Action@*/{}/*@END_MENU_TOKEN@*/) {
                            Text ("Read More")
                                .font(.subheadline)
                                .fontWeight(.medium)
                                .padding(.horizontal, 10)
                                .padding(.vertical, 5)
                                .background(Color.black)
                                .foregroundColor(.white)
                                .overlay (
                                    RoundedRectangle(cornerRadius: 6) .stroke(Color.white, lineWidth: 2)
                            )
                        }.padding(.top, 12)
                        .padding(.horizontal)
                        Spacer()
                    }
                    .padding(.bottom)
                }.background(Color.black)
                .padding(.vertical)
                VStack {
                    HStack {
                        Text("Orlando Eats")
                            .font(.title2)
                            .fontWeight(.bold)
                        Spacer()
                        Text("View all")
                    }.padding(.horizontal)
                    .padding(.top, 20)
                    VStack {
                        ScrollView(.horizontal, showsIndicators: false) {
                            HStack(spacing: 12.0) {
                                ForEach((self.data), id: \.self.restaurantID) { item in
                                    ExploreTile(image: item.restaurantImage, name: item.restaurantName)
                                }
                                
                            }.offset(x: 16)
                            
                        }
                        
                    }.padding(.bottom, 30)
                }
                Spacer()
            }
        }
        .onAppear {
            print("Function called")
            self.getRestaurants()
            
        }
        .navigationBarTitle("")
        .toolbar {
            ToolbarItem(placement: .principal) {
                Image("ue_logo")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 20, height: 20)
            }
        }
    }
    
}

func getRestaurants() {
    self.data.removeAll()
    self.db.collection("businesses").whereField("metro", isEqualTo: self.metro).limit(to: 4).getDocuments() {(querySnapshot, err) in
        if let err = err {
            print("Error getting documents \(err)")
        } else {
            for document in querySnapshot!.documents {
                let id = document.documentID
                let name = document.get("name") as! String
                let image = document.get("photo") as? Array ?? [""]
                self.data.append(RestaurantObject(id: id, name: name, image: image[0] ))
            }
            print("This result returns the following items:")
            print(data.count)
        }
    }
}
}



extension View {
    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
    clipShape( RoundedCorner(radius: radius, corners: corners) )
}
}


struct RoundedCorner: Shape {

var radius: CGFloat = .infinity
var corners: UIRectCorner = .allCorners

func path(in rect: CGRect) -> Path {
    let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
    return Path(path.cgPath)
}
}

class RestaurantObject: ObservableObject {
@Published var restaurantID: String
@Published var restaurantName: String
@Published var restaurantImage: String

init(id: String, name: String, image: String) {
    restaurantID = id
    restaurantName = name
    restaurantImage = image
}
}

However the console shows:

Function called Function called

This result returns the following items: 4 This result returns the following items: 8

Is there something wrong with how the function is written or the order in which it's structured? My intention is to return 4 items from the collection, each containing the "name", and the first photo in the array of "photo".

Jason Tremain
  • 1,259
  • 3
  • 20
  • 35
  • 1
    Why are you expecting different output? Please edit the question to show the documents you expect to receive from this query. Also are you sure that getRestaurants is not getting called twice? – Doug Stevenson Oct 27 '20 at 19:01
  • It does seem to be calling getRestaurants twice though I'm not sure why based on the function. Maybe there's an error in how I'm trying to get the first item in the "photo" array – Jason Tremain Oct 27 '20 at 19:37
  • 1
    Without seeing more code, there's not much we can add. We don't know where the calls are coming from, or why. – Doug Stevenson Oct 27 '20 at 19:45
  • I see others saying there's a bug with SwiftUI lifecycle apps and .onAppear being called twice. – Jason Tremain Oct 27 '20 at 19:53
  • Solved using the solution noted here https://stackoverflow.com/questions/63080830/swifui-onappear-gets-called-twice – Jason Tremain Oct 27 '20 at 20:02
  • Jason - any particular reason why you're not using a snapshot listener? Also, I'd recommend extracting the data access code into a view model / repository (implementing @ObservedObject) – Peter Friese Oct 28 '20 at 07:34

0 Answers0