Пытаюсь передать один документ через Firestore — Swift

#ios #swift #google-cloud-firestore

#iOS #swift #google-облако-firestore

Вопрос:

Вот мой класс customer:

 class Customer {
    // Creating a customer
    let name: String
    let surname: String
    let contactNo: String
    let email: String
   
    init(name: String,surname: String,contactNo: String,email: String) {
        
        self.name = name
        self.surname = surname
        self.contactNo = contactNo
        self.email = email
    }
}
  

Это код, который я использую, который продолжает возвращать ноль:

 class ProfileCus: UIViewController {
    // Labels to display data
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var surnameLabel: UILabel!
    @IBOutlet weak var emailLabel: UILabel!
    @IBOutlet weak var contactLabel: UILabel!
    
    // Reference to customer collection in Firestore
    private var  customerRefCollection = Firestore.firestore().collection("customers")
    
    // Customer Object
    private var customer =  Customer(name: "a",surname: "a",contactNo: "a",email: "a")
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
         getDataFromFirebase{
               self.customerRefCollection = Firestore.firestore().collection("customers")
                
               print(self.customer,"debug step 5")
               self.nameLabel.text = self.customer.name
               self.surnameLabel.text = self.customer.surname
               self.emailLabel.text = self.customer.email
               self.contactLabel.text = self.customer.contactNo
           }
    }
    
    func getDataFromFirebase(completion:@escaping() -> ()){
                    print(self.customer,"debug step 1")
                    let userID = Auth.auth().currentUser?.uid
                    print(userID,"debug step 2")
                // Locate the user information on Firestore
                    customerRefCollection.document(userID!).getDocument { (snapshot, error) in
                    if let err = error {
                        debugPrint("Error fetching documents: (err)")
                    }
                    else {
                        // Ensure that if there's nothing in the document that the function returns
                    guard let snap = snapshot else {return}
                    print(snap, "debug step 3")
                    // Parse the data to the customer model
                    let data = snap.data()
                    
                    let name = data?["name"] as? String ?? ""
                    let surname = data?["surname"] as?  String ?? ""
                    let email = data?["email"] as? String ?? ""
                    let contact = data?["contact no"] as? String ?? ""
                    // Create the customer and pass it to the global variable
                    let cus = Customer(name: name, surname: surname, contactNo: contact, email: email)
                    print(self.customer,"debug step 4")
                    self.customer = cus
                }
                    completion()
            }
    }
}
  

Кто-нибудь, пожалуйста, может помочь мне понять, что я делаю не так, потому что моментальный снимок возвращается, но способ, которым я анализирую данные, неверен, потому что объект customer возвращает значение nil.

Я добавил инструкции печати с тегами, говорящими об отладке шага 1 и т.д., чтобы вы могли следить за тем, что происходит во время выполнения, вот результат:

020-08-13 21:15:20.388052 0200 Clean Wheels[8599: 430648] 6.29.0 — [Firebase / Analytics][I-ACS023012] Клиент с поддержкой сбора аналитики (имя: «a», фамилия: «a», контактное лицо: «a», электронная почта: «a») шаг отладки 1 Необязательно («RWVTDIU ul1eaholpzt1umml0cja2») шаг отладки 2 <FIRDocumentSnapshot: 0x6000017499f0> отладка шаг 3 Клиент (имя: «a», фамилия: «a», контактно: «a», электронная почта: «a») отладка шаг 4 Клиент (имя: «», фамилия: «», контактНо: «», электронная почта: «») отладка шаг 5

Мне кажется, что функция data не является правильной функцией для использования, потому что, когда я жестко кодирую значения, она отображается в представлении профиля пользовательского интерфейса, возможно, есть альтернатива?

Выводите после запуска кода

Комментарии:

1. Пожалуйста, отредактируйте вопрос, чтобы показать документ, который вы пытаетесь получить, и значения переменных, которые вы используете в запросе. Возможно, вы делаете что-то не так с запросом, но мы просто не можем понять, что именно. Я предлагаю также добавить некоторые журналы отладки, чтобы мы могли видеть, как выполняется код. За тем, что у вас есть прямо сейчас, невозможно следить без подробностей.

2. @DougStevenson Я это сделал. Пожалуйста, обратите внимание, что я добавил несколько инструкций печати с шагами отладки, чтобы показать, что происходит. Я надеюсь, что мы сможем решить эту проблему, похоже, что функция data, которую я использую, продолжает возвращать nil.

Ответ №1:

Есть несколько способов, которыми вы можете это сделать, но я бы предложил передать объект customer через обработчик завершения (вызывающему). Вы также могли бы настроить объект customer так, чтобы он делал снимок документа в своем инициализаторе (вместо того, чтобы использовать 4 отдельных свойства) и либо возвращал объект customer, либо nil (для этого потребовался бы отказоустойчивый инициализатор, который невероятно прост). Кроме того, я не видел необходимости объявлять так много свойств экземпляра (во всяком случае, в этом примере), поэтому я их удалил. Я также сделал номер клиента целым числом, а не строкой (чтобы проиллюстрировать, как я бы структурировал данные).

 class Customer {
    let name: String
    let surname: String
    let contactNo: Int // change this back to a string
    let email: String
   
    init(name: String, surname: String, contactNo: Int, email: String) {
        self.name = name
        self.surname = surname
        self.contactNo = contactNo
        self.email = email
    }
}

class ProfileCus: UIViewController {
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var surnameLabel: UILabel!
    @IBOutlet weak var emailLabel: UILabel!
    @IBOutlet weak var contactLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        getCustomer { (customer) in
            if let customer = customer {
                print(customer)
            } else {
                print("customer not found")
            }
        }
    }
    
    private func getCustomer(completion: @escaping (_ customer: Customer?) -> Void) {
        guard let userID = Auth.auth().currentUser?.uid else {
            completion(nil)
            return
        }
        Firestore.firestore().collection("customers").document(userID).getDocument { (snapshot, error) in
            if let doc = snapshot,
                let name = doc.get("name") as? String,
                let surname = doc.get("surname") as? String,
                let contact = doc.get("contact") as? Int, // cast this as a string
                let email = doc.get("email") as? String {
                let customer = Customer(name: name, surname: surname, contactNo: contact, email: email)
                completion(customer)
            } else {
                if let error = error {
                    print(error)
                }
                completion(nil)
            }
        }
    }
}
  

Комментарии:

1. Спасибо! Я ценю это. При запуске кода появляется сообщение «клиент не найден». Я распечатал снимок после вызова функции getDocument, и он действительно содержит документ, однако синтаксический анализ не выполняется. У вас есть какие-либо идеи, почему?

2. Проверьте свою базу данных и убедитесь, что все поля есть в документе, правописание совпадает, и они правильного типа (т. Е. строки).

3. Неважно, я нашел орфографическую ошибку. Все работает, я не мог быть более благодарен. Еще раз спасибо!

4. И последнее, загрузка данных в ярлык занимает около секунды, и это заметно в представлении. Могу ли я добавить что-нибудь, чтобы данные отображались по мере загрузки представления? Вам не нужно показывать мне, как, но, пожалуйста, наставьте меня на правильный путь?

5. Это зависит от вашего вкуса. Вы могли бы заполнить все метки значениями в viewDidLoad перед тем, как выполнить getCustomer вызов. nameLabel.text = "Loading" , например. Но это не самое привлекательное решение. Вы могли бы добавить счетчик загрузки на экран, пока база данных извлекает ваши данные (посмотрите индикаторы активности, у iOS есть готовый к использованию). На самом деле здесь нет волшебства. Независимо от того, как вы хотите, чтобы экран выглядел до поступления данных, отформатируйте его таким образом, прежде чем совершать вызов для получения документа.