昨天已经将环境设定好了,今天要来将新增、读取、更新、删除、排序功能实作出来
我们会需要一个 id 来记录这是哪一笔留言,方便我们後面来处理
然後还需要记录留言人的名字以及留言内容跟最後留言时间
所以就可以将这些东西设计成一个 struct
此外,後面我们还有透过时间来排序留言的需求
所以我们还需要让这个 struct 符合 Comparable 的规范,所以
struct MessageModel: Comparable {
static func < (lhs: MessageModel, rhs: MessageModel) -> Bool {
return lhs.time < rhs.time
}
var id: String
var name: String
var content: String
var time: String
}
宣告两个变数跟一个常数
let dataBase = Firestore.firestore() // 初始化 Firestore
var docRef: DocumentReference? = nil // 建立资料库参考
var messageList = [MessageModel]() // 取得 Struct 内容
override func viewDidLoad() {
super.viewDidLoad()
messageTableView.register(UINib(nibName: "FirestoreDatabaseCell", bundle: nil), forCellReuseIdentifier: "FirestoreDatabaseCell") // 因为我是用 Xib 设计画面,所以要注册一下
messageTableView.delegate = self
messageTableView.dataSource = self
self.fetchMessageFromFirebase() // 这个後面会用到,先写着
}
@IBAction func sendMessageToFirestoreDatabase(_ sender: UIButton) {
self.sendMessageToFirestore()
}
// MARK: - 送出留言到 Cloud Firestore
func sendMessageToFirestore() {
let key = docRef?.documentID
let message = [
"id": key,
"name": self.messagePeopleTF.text!,
"content": self.messageContentTV.text!,
"time": self.getSystemTime()
]
docRef = dataBase.collection("messages").addDocument(data: message as [String : Any], completion: { error in
guard error == nil else {
CustomFunc.customAlert(title: "错误讯息", message: "Error adding document: \(String(describing: error))", vc: self, actionHandler: nil)
return
}
CustomFunc.customAlert(title: "留言已送出!", message: "", vc: self, actionHandler: self.fetchMessageFromFirestore)
})
self.messagePeopleTF.text = ""
self.messageContentTV.text = ""
}
// MARK: - 从 Cloud Firestore 抓取留言
func fetchMessageFromFirestore() {
dataBase.collection("messages").getDocuments { snapshot, error in
if let error = error {
CustomFunc.customAlert(title: "错误讯息", message: "Error getting document: \(String(describing: error))", vc: self, actionHandler: nil)
} else {
self.messageList.removeAll()
for messages in snapshot!.documents {
let messageObject = messages.data(with: ServerTimestampBehavior.none)
// let messageID = messageObject["id"]
let messageName = messageObject["name"]
let messageContent = messageObject["content"]
let messageTime = messageObject["time"]
let message = MessageModel(
id: messages.documentID,
name: messageName as! String,
content: messageContent as! String,
time: messageTime as! String
)
self.messageList.append(message)
}
self.messageTableView.reloadData()
}
}
}
// MARK: - 取得送出/更新留言的当下时间
func getSystemTime() -> String {
let currectDate = Date()
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
dateFormatter.locale = Locale.ReferenceType.system
dateFormatter.timeZone = TimeZone.ReferenceType.system
return dateFormatter.string(from: currectDate)
}
extension CloudFirestoreDatabaseVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messageList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FirestoreDatabaseCell", for: indexPath) as! FirestoreDatabaseCell
cell.messagePeople.text = messageList[indexPath.row].name
cell.messageContent.text = messageList[indexPath.row].content
return cell
}
// MARK: - 更新留言到 Cloud Firestore
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let editAction = UIContextualAction(style: .normal, title: "编辑") { action, view, completeHandler in
let alertController = UIAlertController(title: "更新留言", message: "", preferredStyle: .alert)
alertController.addTextField { textField in
textField.text = self.messageList[indexPath.row].name
}
alertController.addTextField { textField in
textField.text = self.messageList[indexPath.row].content
}
let updateAction = UIAlertAction(title: "更新", style: .default) { action in
let updateMessage = [
"id": self.messageList[indexPath.row].id,
"name": alertController.textFields?[0].text!,
"content": alertController.textFields?[1].text!,
"time": self.getSystemTime()
]
DispatchQueue.main.async {
self.dataBase.collection("messages").document("\(String(describing: self.messageList[indexPath.row].id))").updateData(updateMessage as [AnyHashable : Any])
CustomFunc.customAlert(title: "留言更新成功!", message: "", vc: self, actionHandler: self.fetchMessageFromFirestore)
}
}
let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: nil)
alertController.addAction(updateAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true)
completeHandler(true)
}
let leadingSwipeAction = UISwipeActionsConfiguration(actions: [editAction])
editAction.backgroundColor = UIColor(red: 0.0/255.0, green: 127.0/255.0, blue: 255.0/255.0, alpha: 1.0)
return leadingSwipeAction
}
// MARK: - 从 Cloud Firestore 删除留言
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "删除") { action, view, completeHandler in
DispatchQueue.main.async {
self.dataBase.collection("messages").document("\(String(describing: self.messageList[indexPath.row].id))").delete { error in
if let error = error {
CustomFunc.customAlert(title: "错误讯息", message: "Error removing document: \(String(describing: error))", vc: self, actionHandler: nil)
} else {
CustomFunc.customAlert(title: "已成功删除留言!", message: "", vc: self, actionHandler: self.fetchMessageFromFirestore)
}
}
}
completeHandler(true)
}
let trailingSwipeAction = UISwipeActionsConfiguration(actions: [deleteAction])
return trailingSwipeAction
}
}
// MARK: - 留言排序
@IBAction func sortMessage(_ sender: UIButton) {
self.sortMessageFromFirestore()
}
enum sortMode {
case defaultSort // 预设排序 (从新到旧)
case fromNewToOldSort // 从新到旧
case fromOldToNewSort // 从旧到新
}
func sortMessageFromFirestore() {
let alertController = UIAlertController(title: "请选择留言排序方式", message: "排序方式为送出/更新留言的时间早晚", preferredStyle: .actionSheet)
let defaultAction = UIAlertAction(title: "预设排序", style: .default) { action in
self.sortMessageList(sortMode: .defaultSort)
}
let fromNewToOldAction = UIAlertAction(title: "从新到旧", style: .default) { action in
self.sortMessageList(sortMode: .fromNewToOldSort)
}
let fromOldToNewAction = UIAlertAction(title: "从旧到新", style: .default) { action in
self.sortMessageList(sortMode: .fromOldToNewSort)
}
let closeAction = UIAlertAction(title: "关闭", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
alertController.addAction(fromNewToOldAction)
alertController.addAction(fromOldToNewAction)
alertController.addAction(closeAction)
self.present(alertController, animated: true)
}
func sortMessageList(sortMode: sortMode) {
if (sortMode == .defaultSort || sortMode == .fromNewToOldSort) {
self.messageList.sort(by: >)
} else if (sortMode == .fromOldToNewSort) {
self.messageList.sort(by: <)
}
self.messageTableView.reloadData()
}
本篇的范例程序码:
<<: Day40 ( 游戏设计 ) 反弹球 ( 乒乓球 )
>>: Day40 ( 电子元件 ) 旋钮控制 LED 亮度
「如果怎样就做某件事,否则做另一件事。」这个在聊天时都会拿来用的“程序语法”,来看看在 JS 上怎麽...
前言 生活在网际网路以及智慧型手机普及的今天,与外国朋友聊天、出国旅行、与国外客户开商务会议,纵使不...
Combobox就是组合框,是tkinter.ttk的空件,所以要先import才可以用。他跟ope...
今天要来讲解 DOM 与 this 的关系, 对於 DOM 的操作有两种方式, 第一种是直接将方法写...
如需在地端环境操作 那需要去理解 什麽是node JS 什麽是NPM 需要参照 本地安装 使用 np...