#29 製作 Firestore CRUD Note App
Firebase Firestore / 資料庫增刪查改
功能 Demo
架構
Firestore 資料庫
AppDelegate
import Firebase
外,加入FirebaseApp.configure()
並移除 navigation bar 毛玻璃。
Main.storyboard
Note 結構體
記錄 Note 要包含的六項屬性,屬性初始化改為自訂 init 並傳入字典完成。
★注意 Timestamp 型別資料可以透過 dateValue 方法轉成 Date 型別資料。
NotesManager 類別
管理「得到 notes」、「更新 document」、「更新 document 的 isStarred 欄」、「刪除 document」等函式。
ViewController / NoteViewController
所有筆記區、編輯筆記區
得到 notes
ViewController
viewDidLoad 內,先呼叫 setStarFilterButtonImage 函式,此函式會根據 isStarFiltered 真假值(最初為 false)決定星星 filter 有無填滿(所以最初為無填滿)。
再來根據 isStarFiltered 真假值決定要抓帶有星星的筆記,還是所有筆記。
點按星星 filter,與上面動作的差別在多了切換 isStarFiltered 真假值。
得到 notes
為了讓 Firestore 的 document 有變動時,能即時重抓全部資料,要使用:
來看看 NotesManager 內的 func getNotes(starredOnly: Bool = false)
。
根據 starredOnly 真假值,決定使用哪種 query。starredOnly 為真,query 只包含 isStarred 欄位為 true 的 documents。
使用 data() 方法,從 querySnapshot!.documents 中的每個 queryDocSnapshot(型別是 QueryDocumentSnapshot) 取出字典。再透過 Note 結構體的 initializer 生成 note。
加入 notes 陣列。按 note 的 createdAt 時間由早到晚排序。
用 delegate 和 protocol 回傳 notes 陣列。ViewController notes 屬性更新後記得 tableView.reloadData()
。
回到 ViewController,顯示所有 notes
section 有 notes 的 count 個;每一個 section 有一個 row。notes 資料放到每個 cell 的元件內。
更新 document、更新 document 的 isStarred 欄、刪除 document
選取的 note 傳到編輯頁 NoteViewController
Segue 轉場搭配 prepare 傳 note 給 NoteViewController 的 note 屬性。記得 deselectRow,避免因為維持 select 狀態,造成之後按新增 note 出錯。
NoteViewController
viewDidLoad 內,若 note 為 nil,表示我們在前一頁點選 barButtonItem 新增按鈕並經 segue 而來。所以要做一個新 note 存回 note 屬性。
再來顯示標題、內容,決定星星按鈕有無填滿(由 note 的 isStarred 真假值決定)。
更新 document、更新 document 的 isStarred 欄、刪除 document
・更新 document:
編輯筆記並觸發儲存按鈕後,拿標題文字、內容文字和目前時間更新 note 屬性,再把 note 屬性傳入 NoteManager 的 saveNote 函式。・更新 document 的 isStarred 欄:
點選星星後,note 屬性的 isStarred 欄真假值切換,再根據其真假值決定星星有無填滿,最後把 note 屬性的 docId 跟 isStarred 都傳入 NoteManager 的 updateStarStatus 函式。・刪除 document:
點選刪除後,把 note 屬性傳入 NoteManager 的 deleteNote 函式。
以下解釋 saveNote、updateStarStatus、deleteNote 函式:
saveNote 裡面用 setData 方法更新某 id 的 document(要將 note 轉成字典作為參數傳入)。它能夠聰明地把 Date 型別資料轉成 Timestamp 型別資料。
updateStarStatus 裡面用 updateData 方法更新某 id 之 document(不會覆寫整個 document)。要傳入字典 [“isStarred”: isStarred]
。
deleteNote 裡面用 delete 方法刪除某 id 的 document。
UI 技巧
編輯頁 bodyTextView 的 padding 調整:
bodyTextView.textContainerInset = UIEdgeInsets(top: 30, left: 15, bottom: 30, right: 15)
編輯頁 titleTextField 的 leftView 加入 UIView 物件製造 left padding:
titleTextField.leftViewMode = .always
titleTextField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 19, height: 19))
編輯頁按鈕列 horizontalStackView 的 padding 調整:
horizontalStackView.isLayoutMarginsRelativeArrangement = truehorizontalStackView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 15)
鍵盤出現與消失要調整 bottomConstraint:
點選空白處收鍵盤:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}