【问题标题】:How to refactor duplicate Firestore document IDs in Swift?如何在 Swift 中重构重复的 Firestore 文档 ID?
【发布时间】:2021-08-05 13:59:28
【问题描述】:

我正在使用 Cloud Firestore 做我的第一个 IOS 应用程序,并且必须重复对我的数据库进行相同的查询。我想摆脱重复的代码行。这是文档 ID 重复的 func 示例。我还使用其他查询作为.delete().addSnapshotListener().setData()。我应该以某种方式重构所有这些查询,还是因为它们只用过一次就留下它们?

    @objc func updateUI() {

        inputTranslate.text = ""
        inputTranslate.backgroundColor = UIColor.clear

        let user =  Auth.auth().currentUser?.email
        let docRef = db.collection(K.FStore.collectionName).document(user!)
        docRef.getDocument { [self] (document, error) in

        if let document = document, document.exists {

            let document = document
            let label = document.data()?.keys.randomElement()!
            self.someNewWord.text = label
            
                // Fit the label into screen
            self.someNewWord.adjustsFontSizeToFitWidth = true
            
            self.checkButton.isHidden = false
            self.inputTranslate.isHidden = false
            self.deleteBtn.isHidden = false

        } else {

            self.checkButton.isHidden = true
            self.inputTranslate.isHidden = true
            self.deleteBtn.isHidden = true
            self.someNewWord.adjustsFontSizeToFitWidth = true
            self.someNewWord.text = "Add your first word to translate"

            updateUI()

            }
     }
}
          
@IBAction func checkButton(_ sender: UIButton) {
    
    let user =  Auth.auth().currentUser?.email
    let docRef = db.collection(K.FStore.collectionName).document(user!)
    docRef.getDocument { (document, error) in
        let document = document
        
        let label = self.someNewWord.text!
        let currentTranslate = document!.get(label) as? String

        let translateField = self.inputTranslate.text!.lowercased().trimmingCharacters(in: .whitespaces)

        if translateField == currentTranslate {
            self.inputTranslate.backgroundColor = UIColor.green
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [self] in
                self.inputTranslate.backgroundColor = UIColor.clear
                updateUI()}

        } else {
            self.inputTranslate.backgroundColor = UIColor.red
            self.inputTranslate.shakingAndRedBg()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [self] in
                self.inputTranslate.backgroundColor = UIColor.clear
                self.inputTranslate.text = ""
            }
        }
    }
}

func deletCurrentWord () {

    let user =  Auth.auth().currentUser?.email
    let docRef = db.collection(K.FStore.collectionName).document(user!)
    docRef.getDocument { (document, err) in
        let document = document
        if let err = err {
            print("Error getting documents: \(err)")
            
        } else {
              
            let  array = document!.data()
            let counter = array!.count
                
        if counter == 1 {
                    
                    // The whole document will deleted together with a last word in list.
            let user =  Auth.auth().currentUser?.email
            self.db.collection(K.FStore.collectionName).document(user!).delete() { err in
                if let err = err {
                    print("Error removing document: \(err)")
                } else {
                    self.updateUI()
                }
            }
                        
        } else {
            // A current word will be deleted

            let user =  Auth.auth().currentUser?.email
            let wordForDelete  = self.someNewWord.text!
                    
            self.db.collection(K.FStore.collectionName).document(user!).updateData([
                wordForDelete: FieldValue.delete()
                    ]) { err in
                            
                    if let err = err {
                        print("Error updating document: \(err)")
                    } else {
                        self.updateUI()
                        }
                    }
                }
            }
    }
}

另一个查询示例

       func loadMessages() {
            let user =  Auth.auth().currentUser?.email
            let docRef = db.collection(K.FStore.collectionName).document(user!)
            docRef.addSnapshotListener { (querySnapshot, error) in
            
            self.messages = []
            
            if let e = error {
                print(e)
            } else {
                if let snapshotDocuments = querySnapshot?.data(){
                    
                    for item in snapshotDocuments {
                        
                        if let key = item.key as? String, let translate = item.value as? String {
                                                   
                            let newMessage = Message(key: key, value: translate)
                            self.messages.append(newMessage)
                        }
                    }
                        DispatchQueue.main.async {
                            self.messages.sort(by: {$0.value > $1.value})
                            self.secondTableView.reloadData()
                            let indexPath = IndexPath(row: self.messages.count - 1, section: 0)
                            self.secondTableView.scrollToRow(at: indexPath, at: .top, animated: false)
                            
                        }
                    }
                }
            }
        }
}

【问题讨论】:

    标签: ios swift firebase duplicates


    【解决方案1】:
    enum Error {
        case invalidUser
        case noDocumentFound
    }
    
    func fetchDocument(onError: @escaping (Error) -> (), completion: @escaping (FIRQueryDocument) -> ())  {
        guard let user = Auth.auth().currentUser?.email else {
            onError(.invalidUser)
            return
        }
        db.collection(K.FStore.collectionName).document(user).getDocument { (document, error) in
            if let error = error {
                onError(.noDocumentFound)
            } else {
                completion(document)
            }
        }
    }
    
    func updateUI() {
        fetchDocument { [weak self] error in
            self?.hideShowViews(shouldHide: true, newWordText: nil)
        } completion: { [weak self] document in
            guard document.exists else {
                self?.hideShowViews(shouldHide: true, newWordText: nil)
                return
            }
            self?.hideShowViews(shouldHide: false, newWordText: document.data()?.keys.randomElement())
        }
    }
    
    
    private func hideShowViews(shouldHide: Bool, newWordText: String?) {
        checkButton.isHidden = shouldHide
        inputTranslate.isHidden = shouldHide
        deleteBtn.isHidden = shouldHide
        someNewWord.adjustsFontSizeToFitWidth = true
        someNewWord.text = newWordText ?? "Add your first word to translate"
    }
    

    updateUI 方法可以使用简单的保护语句轻松重构,然后将公共代码取出到单独的函数中。我还使用了[weak self],这样就不会发生内存泄漏或保留周期。

    现在,您可以对其余方法采用类似的方法。

    1. 使用guard let 而不是if let 以避免嵌套。
    2. 使用[weak self] 进行异步调用以避免内存泄漏。
    3. 将通用代码取出到单独的方法中,并使用Bool 标志来隐藏/显示视图。

    第 3 步更新: 您可以为 getDocument()delete() 等创建类似于异步 API 的方法,完成后您可以更新 UI 或执行任何操作。您还可以创建一个单独的类,并将fetchDocument() 和其他类似方法移入其中并使用它们。

    【讨论】:

    • 第 1 步和第 2 步很有用!我感谢你!您能否详细解释一下 step3 如何将通用代码放入单独的方法中?对数据库的引用是一个 if-else 语句,我不知道如何将它拆分为不同的方法。谢谢
    • 你指的是func deletCurrentWord()吗?
    • 我的意思是使用此行的所有方法,包括 func deletCurrentWord()。这是常见的代码行 let user = Auth.auth().currentUser?.email let docRef = db.collection(K.FStore.collectionName).document(user!) docRef.getDocument { [weak self] (document, error)在 guard let document = document 我不能将此引用移动到另一个方法中,因为它是 if-else 语句的一部分。你知道有什么办法吗?
    • 哇,这真的是我想要的!这种重构方式很有趣,对我来说很新鲜。看来这种方式真的很合适,我只需要在这个row guard let document, document.exists else 处修复一个错误“Variable binding in a condition requires an initializer” {Do you know how to fix it?
    • 这是因为该文档不是可选的,因此您可以使用guard document.exists else { 代替。另外,请投票并将答案标记为已接受。谢谢。
    猜你喜欢
    • 2020-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 2019-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多