昨天已经将环境设定好了,今天要来将新增、读取、更新、删除、排序功能实作出来
我们会需要一个 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
}
宣告两个变数,一个是资料库的参考,一个是用来取得 Struct 内容的
var databaseRef: DatabaseReference!
var messageList = [MessageModel]()
override func viewDidLoad() {
super.viewDidLoad()
databaseRef = Database.database().reference().child("messages") // 这个是用来告诉 Firebase,我们要找的资料库路径
messageTableView.register(UINib(nibName: "RealtimeDatabaseCell", bundle: nil), forCellReuseIdentifier: "RealtimeDatabaseCell") // 因为我是用 Xib 设计画面,所以要注册一下
messageTableView.delegate = self
messageTableView.dataSource = self
self.fetchMessageFromFirebase() // 这个後面会用到,先写着
}
用来监听目前资料库内的状态,可以监听的状态有这些
事件类型 | 典型用法 |
---|---|
FIRDataEventTypeChildAdded | 检索项列表,或监听项列表中是否添加了新项。该事件将针对每个现有的子项触发一次,并在每次向指定的路径添加新的子项时再次触发。系统将向监听器传递一个包含新子项的数据的快照。 |
FIRDataEventTypeChildChanged | 监听列表中的项是否发生了更改。每次修改子节点时,均会触发此事件。这包括对子节点的後代所做的任何修改。传递给事件监听器的快照包含子项的更新数据。 |
FIRDataEventTypeChildRemoved | 监听列表中是否有项被移除。移除直接子项将会触发此事件。传递给回调块的快照包含已移除的子项的数据。 |
FIRDataEventTypeChildMoved | 监听经过排序的列表的项顺序是否有更改。只要更新会引发子项重新排序,就会触发此事件。该事件用於已通过 queryOrderedByChild 或 queryOrderedByValue 排序的数据。 |
FIRDataEventTypeValue | 读取并监听对路径中所有内容的更改。 |
``swift= |
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
databaseRef.observe(.value) { snapshot in
if let output = snapshot.value as? [String: Any] {
print("目前资料库内有 \(output.count) 笔留言")
} else {
print("目前资料库内没有留言!")
}
}
}
有增加监听就有移除监听,这样才不会浪费系统资源~
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
databaseRef.removeAllObservers()
}
@IBAction func sendMessageToRealtimeDatabase(_ sender: UIButton) {
self.sendMessageToFirebase()
}
// MARK: - 新增留言到 Firebase Realtime Database
func sendMessageToFirebase() {
let key = databaseRef.childByAutoId().key
let message = [
"id": key,
"name": messagePeopleTF.text!,
"content": messageContentTV.text!,
"time": self.getSystemTime()
]
self.databaseRef.child("\(String(describing: key!))").setValue(message)
CustomFunc.customAlert(title: "留言已送出!", message: "", vc: self, actionHandler: self.fetchMessageFromFirebase)
self.messagePeopleTF.text = ""
self.messageContentTV.text = ""
}
// MARK: - 从 Firebase Realtime Database 读取留言
func fetchMessageFromFirebase() {
self.databaseRef.observe(.value) { snapshot in
if (snapshot.childrenCount > 0) {
self.messageList.removeAll()
for messages in snapshot.children.allObjects as! [DataSnapshot] {
let messageObject = messages.value as? [String: AnyObject]
let messageID = messageObject?["id"]
let messageName = messageObject?["name"]
let messageContent = messageObject?["content"]
let messageTime = messageObject?["time"]
let message = MessageModel(
id: messageID as! String,
name: messageName as! String,
content: messageContent as! String,
time: messageTime as! String
)
self.messageList.append(message)
}
self.messageTableView.reloadData()
} else {
self.messageList.removeAll()
self.messageTableView.reloadData()
}
}
}
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 RealtimeDataBaseVC: 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: "RealtimeDatabaseCell", for: indexPath) as! RealtimeDatabaseCell
cell.messagePeople.text = messageList[indexPath.row].name
cell.messageContent.text = messageList[indexPath.row].content
return cell
}
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()
]
self.databaseRef.child("\(String(describing: self.messageList[indexPath.row].id))").setValue(updateMessage)
CustomFunc.customAlert(title: "留言更新成功!", message: "", vc: self, actionHandler: nil)
}
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
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "删除") { action, view, completeHandler in
self.databaseRef.child(self.messageList[indexPath.row].id).setValue(nil)
completeHandler(true)
}
let trailingSwipeAction = UISwipeActionsConfiguration(actions: [deleteAction])
return trailingSwipeAction
}
}
// MARK: - 留言排序
@IBAction func sortMessage(_ sender: UIButton) {
self.sortMessageFromFirebase()
}
enum sortMode {
case defaultSort // 预设排序 (从新到旧)
case fromNewToOldSort // 从新到旧
case fromOldToNewSort // 从旧到新
}
func sortMessageFromFirebase() {
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()
}
本篇的范例程序码:
基本上跟POST是有点类似的作法 通常用於资料更新(所以资料必须是已存在於目前db的) 新增额外的a...
我们继续透过 LeetCode #1 Two Sum 来实际感受解决问题的过程 ( 题目连结 ) 一...
连线设定其实也没什麽好介绍的,改 env 这种事 sail 已经弄好了。 即便现在,用 compos...
到了倒数第二天,一直在想自己该写什麽,在参加这个比赛之前,自己常埋首在自以为是的开发中,无论遇到什麽...
PHP 干古 最早於 1994 由 Rasmus Lerdorf 用 C 语言开发的 CGI 程序,...