【问题标题】:Struggling to pass a single document through Firestore - Swift努力通过 Firestore 传递单个文档 - Swift
【发布时间】:2020-08-13 18:35:13
【问题描述】:

这是我的客户类别:

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
    }
}

这是我正在使用的代码,它一直返回 nil:

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()
            }
    }
}

谁能帮我理解我做错了什么,因为快照确实返回,但我解析数据的方式是错误的,因为客户对象返回 nil。

我添加了带有标签的打印语句,说明调试步骤 1 等,因此您可以跟踪运行时发生的情况,这是输出:

020-08-13 21:15:20.388052+0200 Clean Wheels[8599:430648] 6.29.0 - [Firebase/Analytics][I-ACS023012] 分析收集已启用 客户(姓名:“a”,姓:“a”,contactNo:“a”,电子邮件:“a”)调试步骤 1 可选(“RWVTDIUuL1eahOLpZT1UmMl0cja2”)调试步骤 2 调试步骤 3 客户(姓名:“a”,姓:“a”,contactNo:“a”,电子邮件:“a”)调试步骤 4 Customer(name: "", surname: "", contactNo: "", email: "") 调试步骤 5

在我看来,数据函数似乎不是正确使用的函数,因为当我对它显示在 UI 配置文件视图中的值进行硬编码时,是否有替代方法?

Output once the code runs

【问题讨论】:

  • 请编辑问题以显示您尝试获取的文档,以及您在查询中使用的变量的值。您可能对查询做错了什么,但我们只是看不到那是什么。我建议还添加一些调试日志,以便我们可以看到代码是如何执行的。如果没有详细信息,您现在所拥有的就无法遵循。
  • @DougStevenson 我已经这样做了。请注意,我添加了一些带有调试步骤的打印语句,以帮助显示正在发生的事情。我希望我们能解决这个问题,好像我使用的数据函数一直返回 nil。

标签: ios swift google-cloud-firestore


【解决方案1】:

有很多方法可以做到这一点,但我建议将客户对象通过完成处理程序(到调用者)。您还可以将客户对象配置为在其初始化程序中获取文档快照(而不是获取 4 个单独的属性)并返回客户对象或 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)
            }
        }
    }
}

【讨论】:

  • 谢谢!我很欣赏这个。当我运行代码时,它说“找不到客户”。我在 getDocument 函数调用之后打印了快照,它确实包含文档,但是没有进行解析。你知道为什么吗?
  • 检查您的数据库并确保所有字段都在文档中,拼写匹配,并且它们是正确的类型(即字符串)。
  • 没关系,我发现了拼写错误。一切正常,我感激不尽。再次感谢您!
  • 最后一件事,数据需要大约一秒钟才能加载到标签中,并且在视图中很明显。我可以添加一些东西让数据在视图加载时显示吗?你不需要告诉我怎么做,但请让我走上正确的道路?
  • 这取决于你的口味。在进行getCustomer 调用之前,您可以使用viewDidLoad 中的值填充所有标签。例如nameLabel.text = "Loading"。但这不是最有吸引力的解决方案。您可以在数据库获取数据时在屏幕上添加一个加载微调器(查找活动指示器,iOS 有一个可以使用)。这里没有魔法,真的。无论您希望屏幕在数据到达之前是什么样子,都可以在调用以获取文档之前将其格式化。
猜你喜欢
  • 1970-01-01
  • 2019-08-25
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
  • 2017-11-20
  • 2018-10-07
  • 1970-01-01
  • 2023-04-03
相关资源
最近更新 更多