【问题标题】:Updating data in the firebase更新 Firebase 中的数据
【发布时间】:2021-03-09 21:28:55
【问题描述】:

我正在尝试制作包含 firebase 代码的小型应用程序以了解更多信息。所以在这里我做了一个待办事项列表应用程序,我能够将任务添加到firebase并且我能够删除它,我遇到的问题是更新任务的状态(isComplete:Bool)我不知道如何编写firebase代码来更新数据。我读到的几乎所有教程都是关于上传到实时数据库的数据,而我正在使用云,所以我无法弄清楚。在这里我写了这段代码,所以当任务完成时,我选择了圆圈变成 checkmark.circle 的单元格,但当然数据库没有更新..

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        let cell = tableView.cellForRow(at: indexPath) as! TodoCell

        if cell.isComplete == false{
           cell.doneButton.image = UIImage(systemName: "checkmark.circle")
           cell.isComplete = true
  
       } else {
           cell.doneButton.image = UIImage(systemName: "circle")
           cell.isComplete = false

}
}
}

向 Firebase 代码添加任务

    public func postTask(task:String, isComplete: Bool,
                            completion: @escaping (Result<Bool, Error>) -> ()) {
      guard let user = Auth.auth().currentUser else {
          return
      }
  
        let documentRef = db.collection(DatabaseService.itemsCollection).document()

        db.collection(DatabaseService.usersCollection).document(user.uid).
        collection(DatabaseService.tasksCollection).
        document(documentRef.documentID).setData(["task" : task,
                                                  "isComplete": isComplete,
                                                  "taskId": documentRef.documentID])
        { (error) in


        if let error = error {
          completion(.failure(error))
        } else {
          completion(.success(true))
        }
      }
    }
    

快照监听器

override func viewDidAppear(_ animated: Bool) {
      super.viewDidAppear(true)

        guard let user = Auth.auth().currentUser else {
            return
        }
        listener = Firestore.firestore().collection(DatabaseService.usersCollection)
      .document(user.uid).collection(DatabaseService.tasksCollection)
      .addSnapshotListener({ [weak self] (snapshot, error) in

          if let error = error {
            DispatchQueue.main.async {
              self?.showAlert(title: "Try Again", message: 
               error.localizedDescription)
            }
          } else if let snapshot = snapshot {
            let task = snapshot.documents.map { TasksList($0.data()) }
            self?.todoItems = task
          }
        })
    }

根据@bkbkchoy 的回答,我编写了这些代码:

func updateTask(task: TasksList,
                isComplete: Bool,
                        completion: @escaping (Result<Bool, Error>) -> ()) {
  guard let user = Auth.auth().currentUser else { return }

    db.collection(DatabaseService.usersCollection).document(user.uid)
   .collection(DatabaseService.tasksCollection).document(task.taskId)
   .updateData(["isComplete": isComplete]) { (error) in
          if let error = error {
            completion(.failure(error))
          } else {
            completion(.success(true))
    }
  }
}
    
}

在 didSelectRow 下

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
     
        let cell = tableView.cellForRow(at: indexPath) as! TodoCell
        
       let isComplete = false
       
        
        if task2.isComplete == false{
           cell.doneButton.image = UIImage(systemName: "checkmark.circle")
           cell.doneButton.tintColor = .systemBlue
           cell.isComplete = true

       } else {
           cell.doneButton.image = UIImage(systemName: "circle")
           cell.doneButton.tintColor = .systemGray
           cell.isComplete = false


}
        updateStatus(isComplete: isComplete)

        
    }
       
   private func updateStatus(isComplete: Bool) {
        databaseService.updateTask(task: task2, isComplete: isComplete) 
          { [weak self] (result) in
              switch result {
              case .failure(let error):
                DispatchQueue.main.async {
                  self?.showAlert(title: "Try again", message: error.localizedDescription)
                }
              case .success:
               break
       }
      }
     }
    }

但我遇到了一个错误:

没有要更新的文档:project/todo-list/database/(default)/documents/users/jYZmghQeXodeF2/tasks/1

struct TasksList {
  let task: String
  let taskId: String
  let isComplete: Bool


}

extension TasksList {
  init(_ dictionary: [String: Any]) {
    self.task = dictionary["task"] as? String ?? ""
    self.taskId = dictionary["taskId"] as? String ?? ""
    self.isComplete = dictionary["isComplete"] as? Bool ?? false
  }
}

【问题讨论】:

  • TasksList包含什么(为什么不简单Task,一个实例代表一个任务)?
  • @vadian 我用答案更新了我的问题

标签: swift firebase google-cloud-firestore


【解决方案1】:

有几种方法可以更新 Cloud Firestore 中的文档:

  1. 使用setData重写特定属性:

db.collection(DatabaseService.usersCollection)
    .document(user.uid)
    .collection(DatabaseService.tasksCollection)
    .document(task.taskId)
    .setData(["isComplete": isComplete], merge: true)

注意:如果您使用setData,则必须包含merge: true 以覆盖现有文档的单个属性,否则将覆盖整个文档。

  1. 使用updateData

db.collection(DatabaseService.usersCollection)
    .document(user.uid)
    .collection(DatabaseService.tasksCollection)
    .document(task.taskId)
    .updateData(["isComplete": isComplete]) { err in 
        if let err = err {
            print("error updating document: \(err)")
        } else {
            print("doc successfully updated")
        }
    }

Firestore 有一些很棒的在线文档。如果您想了解更多关于更新/添加数据的信息here's a good place to start.

【讨论】:

  • 我根据你的回答用我写的代码更新了我的问题,我得到的错误请检查一下
  • 您得到的错误表明文档尚未在该路径创建。如果您想进行更新并且不确定文档是否存在,更安全的路径是使用带有setData merge: true 路由的选项 1。使用 setData,如果文档不存在,它将创建一个文档,或者如果文档已经存在,则合并它(当设置了合并标志时)。仅当您确信文档存在时才应使用更新,否则会引发错误。
  • 谢谢..文档是存在的,但我找出了导致错误的原因。 :)
  • 很高兴你把它整理出来了!出了什么问题?
  • task: TasksList 当我在 didSelectAtRow 下使用它时出现错误,我不能使用 tasksList,我应该使用值 insted,所以我写了变量 var task2 = TaskList(task: "", taskId: "1", isComplete: false)
【解决方案2】:

你的方法行不通。

单元格只是view,它显示UI元素及其值,数据源是model TasksList(为什么不简单Task) .

单元格被重复使用,当用户滚动时,您将丢失单元格中的isCompleted 信息。您必须更新 model 并重新加载 view

首先将模型声明为Task,将isComplete声明为variable。根据命名准则task 应该是nametitletaskId 应该只是id

struct Task {
  let task: String
  let taskId: String
  var isComplete: Bool
}

cellForRow中根据模型设置单元格中的UI元素

let task = todoItems[indexPath.row]
let imageName = task.isComplete ? "checkmark.circle" : "circle"
cell.doneButton.image = UIImage(systemName: imageName)
cell.doneButton.tintColor = task.isComplete ? .systemBlue : .systemGray

在模型中的didSelect切换isComplete,重新加载行并保存任务

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    todoItems[indexPath.row].isComplete.toggle()
    tableView.reloadRows(at: [indexPath], with: .none)
    let task = todoItems[indexPath.row]
    updateTask(task: task, isComplete: task.isComplete) { result in print(result) }
}

由于整个任务已经移交,updateTask中不需要第二个参数isComplete

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多