#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 есть готовый к использованию). На самом деле здесь нет волшебства. Независимо от того, как вы хотите, чтобы экран выглядел до поступления данных, отформатируйте его таким образом, прежде чем совершать вызов для получения документа.