如何在 Swift 中重构重复的 Firestore 文档 ID?

How to refactor duplicate Firestore document IDs in Swift?

我正在使用 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: {[=12=].value > .value})
                            self.secondTableView.reloadData()
                            let indexPath = IndexPath(row: self.messages.count - 1, section: 0)
                            self.secondTableView.scrollToRow(at: indexPath, at: .top, animated: false)
                            
                        }
                    }
                }
            }
        }
}
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方法可以使用简单的guard语句轻松重构,然后将公共代码取出到一个单独的函数中。我还使用了 [weak self] 这样就不会发生内存泄漏或保留循环。

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

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

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