Swift Firestore 如何向列表新增内容且不覆盖原有存储数据?
核心问题定位
当前实现存在两个直接导致功能不符合需求的设计问题:
- 写入端使用
setData(["text": text]),会全量覆盖文档原有内容,直接将text字段的存储值替换为最新输入的单条字符串 - 存储结构设计为单字符串字段,本身不具备保存多条内容列表的能力
可落地修改方案
- 调整数据存储结构:将原单字符串
text字段改为存储字符串数组,支持保存多条输入内容 - 替换写入逻辑:使用Firestore内置的
FieldValue.arrayUnion方法追加元素,该方法无需客户端提前拉取旧数据再拼接,可避免多端同时写入时的内容覆盖、数据丢失问题 - 调整实时监听逻辑:读取数组字段的全部内容,拼接为适配UI展示的字符串后更新到页面Label
修改后的可运行代码
import UIKit import FirebaseFirestore class ViewController: UIViewController, UITextFieldDelegate { let database = Firestore.firestore() private let label: UILabel = { let label = UILabel() label.textAlignment = .center label.numberOfLines = 0 return label }() private let field: UITextField = { let field = UITextField() field.placeholder = "enter text.." field.layer.borderWidth = 1 field.layer.borderColor = UIColor.black.cgColor return field }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(label) view.addSubview(field) field.delegate = self let docRef = database.document("ios/ex") docRef.addSnapshotListener {[weak self] snapshot, error in guard let data = snapshot?.data(), error == nil else { return } guard let textList = data["text"] as? [String] else { self?.label.text = "" return } let displayText = textList.joined(separator: "\n") DispatchQueue.main.async { self?.label.text = displayText } } } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() field.frame = CGRect(x: 1, y: view.safeAreaInsets.top+10, width: view.frame.size.width-20, height: 50) label.frame = CGRect(x: 1, y: view.safeAreaInsets.top+10+60, width: view.frame.size.width-20, height: 100) } func textFieldShouldReturn(_ textField: UITextField) -> Bool { if let text = textField.text, !text.isEmpty { savedData(text: text) textField.text = "" } return true } func savedData(text: String){ let docRef = database.document("ios/ex") docRef.setData([ "text": FieldValue.arrayUnion([text]) ], merge: true) } }
补充说明
FieldValue.arrayUnion会自动过滤重复的追加内容,如果需要保留所有输入(哪怕内容重复),可以先读取文档现有数组,拼接新内容后再通过updateData写入- 首次调用写入时如果目标文档不存在,带
merge: true参数的setData会自动创建对应文档,不会触发报错 - 如果需要兼容历史存储的单字符串格式旧数据,可在监听逻辑中增加类型判断:检测到text字段为String类型时,将该值转为数组的初始元素,后续的追加逻辑可正常运行
内容的提问来源于stack exchange,提问作者Arash Kalhori
相关产品推荐
相关产品推荐

