我正在Swift中开发一个育儿应用程序,我正在使用Firebase Cloud Firestore为我的Swift应用程序保存数据。该应用程序的一部分是父母可以添加他们的孩子并在应用程序中显示它们的地方。
我创建了一个子模型,我在将新子项添加到tableview时使用。
儿童模型
protocol DocumentSerializable {
init?(dictionary:[String:Any])
}
// Child Struct
struct Child {
var name: String
var age: Int
var timestamp: Date
var imageURL: String
var dictionary:[String:Any] {
return [
"name":name,
"age":age,
"timestamp":timestamp,
"imageURL":imageURL
]
}
}
//Child Extension
extension Child : DocumentSerializable {
init?(dictionary: [String : Any]) {
guard let name = dictionary["name"] as? String,
let age = dictionary["age"] as? Int,
let imageURL = dictionary["imageURL"] as? String,
let timestamp = dictionary["timestamp"] as? Date else {
return nil
}
self.init(name: name, age: age, timestamp: timestamp, imageURL: imageURL)
}
}
我通过在我的视图中运行一个函数将我的appview中的数据添加到我的tableview中,加载,loadData()
我首先设置了2个变量:
//firestore connection
var db:Firestore!
//child array
var childArray = [Child]()
viewDidLoad中
override func viewDidLoad() {
super.viewDidLoad()
//Connect to database
db = Firestore.firestore()
// call load data function
loadData()
checkForUpdates()
}
loadData()函数连接到登录的用户数据,然后抓取用户' children'文档,并使用子对象协议将子项添加到childArray。
func loadData() {
// create ref to generate a document ID
let user = Auth.auth().currentUser
db.collection("users").document((user?.uid)!).collection("children").getDocuments() {
QuerySnapshot, error in
if let error = error {
print("\(error.localizedDescription)")
} else {
// get all children into an array
self.childArray = QuerySnapshot!.documents.flatMap({Child(dictionary: $0.data())})
DispatchQueue.main.async {
self.childrenTableView.reloadData()
}
}
}
}
我通过返回childArray计数得到numberOfRowsInSection:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return childArray.count
}
我使用自定义单元格类填充cellForRow并使用如下的childArray内容:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = childrenTableView.dequeueReusableCell(withIdentifier: "Cell") as! ChildCellTableViewCell
let child = childArray[indexPath.row]
cell.childNameLabel.text = "\(child.name)"
cell.childAgeLabel.text = "Age: \(child.age)"
let url = URL(string: "\(child.imageURL)")
cell.childImage.kf.setImage(with: url)
cell.childNameLabel.textColor = UIColor.white
cell.childAgeLabel.textColor = UIColor.white
cell.backgroundColor = UIColor.clear
return cell
}
我希望能够滑动以删除每个表格行单元格,因此我实现了以下内容:
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
childArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
这会成功从应用中删除该行。但我的问题是我不确定如何让删除的行从Firestore数据库中删除匹配的数据。
更复杂的是,因为每个孩子都有一个存储在Firebase存储中的图像,我还需要以某种方式删除这个图像。图像URL存储在imageURL下的子文档中。
我很感激任何指导或指向正确的方向,我找不到很多关于Firestore和UITableViews的文档,所以不知道接下来会尝试什么?
更新 在' canEditRow' 功能中,我设法从我删除的表格行中删除Firebase存储中的子图像,但我很难从Firestore中删除子文档。我可以查询我需要删除的文档,但不知道如何从这个查询中运行delete()函数?
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
// 1. First Delete the childs image from storage
let storage = Storage.storage()
let childsImageURL = childArray[indexPath.row].imageURL
let storageRef = storage.reference(forURL: childsImageURL)
storageRef.delete { error in
if let error = error {
print(error.localizedDescription)
} else {
print("File deleted successfully")
}
}
// 2. Now Delete the Child from the database
let name = childArray[indexPath.row].name
let user = Auth.auth().currentUser
let query = db.collection("users").document((user?.uid)!).collection("children").whereField("name", isEqualTo: name)
print(query)
childArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
答案 0 :(得分:2)
我想我已经设法解决了这个问题,而且它似乎正在发挥作用。在'canEditRow'功能(数字2)中,我现在可以找到特定的子项(在刷新要删除的表格单元格时),并在Firebase Firestore数据库中删除相同的子项。
我不确定这是否是正确的方法,或者如果我错过任何错误检查,但这一切似乎都有效。
如果有人能在这里发现任何错误,请告诉我,我真的想确保使用安全并且所有后备都已到位。
所以这就是我所做的让整个事情发挥作用。
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
// 1. First Delete the childs image from storage
let storage = Storage.storage()
let childsImageURL = childArray[indexPath.row].imageURL
let storageRef = storage.reference(forURL: childsImageURL)
storageRef.delete { error in
if let error = error {
print(error.localizedDescription)
} else {
print("File deleted successfully")
}
}
// 2. Now Delete the Child from the database
let name = childArray[indexPath.row].name
let user = Auth.auth().currentUser
let collectionReference = db.collection("users").document((user?.uid)!).collection("children")
let query : Query = collectionReference.whereField("name", isEqualTo: name)
query.getDocuments(completion: { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
} else {
for document in snapshot!.documents {
//print("\(document.documentID) => \(document.data())")
self.db.collection("users").document((user?.uid)!).collection("children").document("\(document.documentID)").delete()
}
}})
// 3. Now remove from TableView
childArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
答案 1 :(得分:0)
您应该将文档ID添加到模型中:
struct Child {
var id: String
var name: String
var age: Int
var timestamp: Date
}
构造函数应为:
init?(dictionary: [String : Any], id: String) {
guard let name = dictionary["name"] as? String,
let age = dictionary["age"] as? Int,
let imageURL = dictionary["imageURL"] as? String,
let timestamp = dictionary["timestamp"] as? Date else {
return nil
}
self.init(id: id, name: name, age: age, timestamp: timestamp, imageURL: imageURL)
}
在loadData()方法中应该是:
self.childArray = QuerySnapshot!.documents.flatMap({Child(dictionary: $0.data(), id: $0.documendID)})
这样,您无需查询文档,便拥有并直接将其删除:
self.db.collection("users").document((user?.uid)!).collection("children").document(childArray[indexPath.row].id)).delete()
最后一个问题:为什么要对已经为String类型的变量进行插值以获得String值?
答案 2 :(得分:0)
快速4和5
import FirebaseFirestore
var database : Firestore!
override func viewDidLoad() {
super.viewDidLoad()
db = Firestore.firestore()
}
private func remove(_ id: String) -> Void {
database.collection("User").whereField("id", isEqualTo: id).getDocuments { (querySnapshot, error) in
if error != nil {
print(error)
} else {
for document in querySnapshot!.documents {
document.reference.delete()
}
}
}
}