สวัสดีทุกคน! ในบทความนี้เราจะเรียนรู้วิธีเพิ่มฐานข้อมูล Realm เข้าแอป iOS
เราจะสร้างแอป ToDo ง่ายๆ เพื่อคุณเรียนรู้วิธีทำ CRUD (Create, Read, Update, Delete) Operations ในฐานข้อมูล Realm
Realm คืออะไร?
Realm เป็นฐานข้อมูลมือถือโอเพนซอร์ส ที่เป็นมิตรกับนักพัฒนาและใช้งานง่าย คุณยังสามารถใช้เป็นทางเลือกแทน Core Data ในแอป iOS ได้
Realm เป็น Cross-platform Mobile Database หมายความว่าคุณสามารถใช้ใน Native Android และ iOS Apps และ Cross-platform Apps เช่น React Native รองรับ Objective-C, Swift, Java, Kotlin, C#, และ JavaScript
วิธีตั้งค่า Realm ในโปรเจกต์ iOS ของคุณ
เราสามารถเพิ่ม Realm เข้าโปรเจกต์ iOS ด้วย SPM (Swift Package Manager), CocoaPods, หรือ Carthage ที่นี่เราจะใช้ CocoaPods เพื่อเพิ่ม Realm Pod เข้าโปรเจกต์ iOS
- เปิด Xcode สร้างโปรเจกต์ iOS App ใหม่แบบว่าง ด้วย UIKit และ Swift โดยไม่ใช้ Core Data
- ปิด Xcode เปิด Terminal ไปที่ไดเรกทอรีโปรเจกต์
- รันคำสั่งต่อไปนี้เพื่อสร้าง Podfile
pod init
4. ตอนนี้ List เนื้อหาไดเรกทอรี จะเห็น Podfile ใหม่ เปิดด้วย Text Editor ใดๆ (ที่นี่ใช้ Vim) แก้ Podfile ให้คล้ายภาพด้านล่าง Save และปิด
ตอนนี้เราระบุ Dependency สำหรับ Realm DB แล้ว ติดตั้ง Dependencies ด้วยคำสั่ง:
pod install
เห็นว่าเราเพิ่ม Realm DB Dependency ในโปรเจกต์ iOS สำเร็จ รันคำสั่งเพื่อเปิดโปรเจกต์ใน Xcode:
open YOUR_APP_NAME.xcworkspace
หมายเหตุ: หลังเปิด Xcode ตรวจสอบให้แน่ใจว่า Build โปรเจกต์ด้วย Command+B
วิธีออกแบบ User Interface ใน Realm
เราจะทำ UI ให้เรียบง่าย เปิด Main.storyboard สร้าง UI เรียบง่ายตามภาพด้านล่าง โดยเพิ่ม Table View พร้อม Prototype Cell จากนั้น Embed Navigation Controller และสร้าง IBOutlets สำหรับ TableView ใน ViewController.swift:
วิธีสร้าง Data Model ใน Realm
ในแอป ToDo ของเรา แต่ละ Task มีชื่อ Task และ Task ID เราจะสร้าง Model Class แทน ToDo Task ใน Project Navigator คลิกขวาสร้าง Swift File ใหม่ ใส่โค้ดด้านล่าง:
import Foundation
import RealmSwift
class ToDoTask: Object {
@objc dynamic var tasknote: String?
@objc dynamic var taskid: String?
}
ที่นี่เราสร้าง Model Class ชื่อ ToDoTask สืบทอดจาก Class Object ซึ่งมาพร้อมกับ RealmDB Class นี้จัดการกระบวนการใต้ฮู้ดทั้งหมดของการบันทึกข้อมูลที่สร้างด้วย Model Class นี้ในฐานข้อมูล
เราเพิ่ม Properties สองอย่าง: tasknote คือ Task ที่ต้องทำ และ taskid — ทั้งคู่เป็น String @objc หมายถึงโค้ด Swift ของคุณมองเห็นได้จาก Objective-C และ dynamic หมายถึงคุณต้องการใช้ Objective-C Dynamic Dispatch
ฟังก์ชัน CRUD App พื้นฐาน
แอปของเราจะทำฟังก์ชันต่อไปนี้:
- รับ Input จากผู้ใช้ด้วย AlertViewController
- เพิ่ม Input เข้า Database และ Table View
- อนุญาตให้ผู้ใช้แก้ไข Input
- Swipe เพื่อลบ Row ลบข้อมูลจาก Table View และ Database
- ดึงข้อมูลทั้งหมด (ถ้ามี) จาก Database แสดงใน Table View
วิธีรับ Input จากผู้ใช้ด้วย AlertViewController
เปิด ViewController.swift ใส่โค้ดด้านล่างภายในเมธอด viewDidLoad() และสร้างฟังก์ชันใหม่ชื่อ addTask() ใส่โค้ดแสดง Alert View Controller พร้อม Text Box รับ Input จากผู้ใช้
ตอนนี้เมื่อกดปุ่ม Right Bar Button จะเรียกฟังก์ชัน addTask() ซึ่งจะแสดง alertviewcontroller พร้อม Text Field รับ Input
navigationItem.rightBarButtonItem = UIBarButtonItem(image: .add, style: .done, target: self, action: #selector(addTask))
navigationController?.navigationBar.prefersLargeTitles = true
title = "RealmDB"
@objc func addTask() {
let ac = UIAlertController(title: "Add Note", message: nil, preferredStyle: .alert)
ac.addTextField(configurationHandler: .none)
ac.addAction(UIAlertAction(title: "Add", style: .default, handler: { (UIAlertAction) in
if let text = ac.textFields?.first?.text {
print(text)
}
}))
ac.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(ac, animated: true, completion: nil)
}
วิธีเพิ่ม Input เข้า Database และ Table View
เพื่อบันทึกข้อมูลลง Realm ก่อนอื่นเราต้องได้ Instance สำหรับ Realm ซึ่งผ่านเข้าถึงทุกเมธอดที่ต้องการสำหรับ CRUD Operations สร้าง Property ประเภท Realm ใน ViewController.swift และ Initialize ใน viewDidLoad()
var realmDB: Realm!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(image: .add, style: .done, target: self, action: #selector(addTask))
navigationController?.navigationBar.prefersLargeTitles = true
title = "RealmDB"
realmDB = try! Realm()
}
สร้าง Array ว่างประเภท DataModel (ToDoTask) Array นี้จะเก็บ Tasks ทั้งหมดที่ต้องเพิ่มใน Table View และ Database
ตอนนี้ภายในฟังก์ชัน addTask() แก้ไข Closure ของ Action Add ให้รับ User Input และสร้าง Random ID สำหรับ Input นั้น จากนั้น Append เข้า Array และบันทึกลง Database
var tasks = [ToDoTask]()
if let text = ac.textFields?.first?.text {
// Add data to data model array
let t = ToDoTask()
t.taskid = UUID().uuidString
t.tasknote = text
self.tasks.append(t)
// Add data to database
try! self.realmDB.write {
self.realmDB.add(t)
}
// Update table view UI
self.tasktv.reloadData()
}
ตอนนี้รันแอป ข้อมูลจะบันทึกใน Database แต่จะไม่แสดงใน Table View เพราะเรายังไม่ได้ Implement Delegate Methods
ทำให้ ViewController Class 实作 UITableViewDelegate และ UITableViewDataSource Protocols และเพิ่ม Protocol Stubs
ตอนนี้ภายในเมธอด numberOfRowsInSection คืนค่า Count ของ Array Tasks ซึ่งให้จำนวน Rows ที่จะเพิ่มใน Table View เท่ากับจำนวน Elements ใน Tasks Array
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count;
}
สิ่งต่อไปคือระบุเนื้อหาในแต่ละ Row ทำได้ด้วย Delegate Method cellForRowAt ที่นี่เรา Dequeue Cell ด้วย Identifier ที่ระบุใน Storyboard และตั้ง Label Text เป็น Property tasknote ของ Element ใน Tasks Array
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") {
cell.textLabel?.text = tasks[indexPath.row].tasknote
return cell
}
return UITableViewCell()
}
วิธีอนุญาตให้ผู้ใช้แก้ไข Input
ตอนนี้เราต้องอนุญาตให้ผู้ใช้แก้ไข Task ที่ป้อน และอัปเดตการเปลี่ยนแปลงใน Database และ UI พร้อมกัน ทำได้ด้วยวิธีคล้ายการรับ Input สร้างเมธอด Delegate didSelectRowAt ซึ่งจะถูกเรียกเมื่อผู้ใช้แตะ Table View Row
ใส่โค้ดด้านล่าง ซึ่งแสดง AlertViewController พร้อม Text View จากนั้นอัปเดตเนื้อหา Cell ด้วยข้อความที่ป้อน และอัปเดตเนื้อหา Database พร้อมกัน
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let tasktomodify = tasks[indexPath.row]
let ac = UIAlertController(title: "Update task", message: nil, preferredStyle: .alert)
ac.addTextField(configurationHandler: .none)
ac.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (UIAlertAction) in
if let text = ac.textFields?.first?.text {
if(!text.isEmpty) {
try! self.realmDB.write({
tasktomodify.tasknote = text
})
self.tasktv.reloadData()
}
}
}))
present(ac, animated: true, completion: nil)
}
วิธี Swipe ลบ Row & ลบข้อมูลจาก Table View และ Database
ที่นี่เราจะ Implement Swipe to Delete ใน Table View ให้ผู้ใช้ลบ Task ได้ แต่ข้างใต้ฮู้ด เมื่อผู้ใช้ Swipe Delete Row ควรลบข้อมูลจาก Database, Data Model Array และอัปเดต UI Table View
ทำได้โดย Implement Delegate Method commit editingStyle และใส่โค้ดต่อไปนี้:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let tasktoDelete = tasks[indexPath.row]
try! realmDB.write({
realmDB.delete(tasktoDelete)
self.tasks.remove(at: indexPath.row)
self.tasktv.deleteRows(at: [indexPath], with: .fade)
})
}
}
วิธีดึงข้อมูลทั้งหมด (ถ้ามี) จาก Database แสดงใน Table View
ตอนนี้เราจะ Implement Operation สุดท้ายคือ Read ทุกครั้งที่ผู้ใช้เปิดแอป ควรดึงข้อมูลจาก Database (ถ้ามีข้อมูล) และแสดงใน Table View
ทำได้โดยสร้างฟังก์ชัน getTodo ใน View Controller Swift File ใส่โค้ดต่อไปนี้:
func getTodos() {
// Get all data from database
let notes = realmDB.objects(ToDoTask.self)
// Clear model data array to prevent duplicates
self.tasks.removeAll()
/* If fetched data is not empty then add to model data array and update UI */
if(!notes.isEmpty) {
for n in notes {
self.tasks.append(n)
}
self.tasktv.reloadData()
}
}
เคล็ดลับพิเศษ: วิชามองเนื้อหา Database ใน iOS Simulator
ตอนนี้รันแอป จะเห็นว่าทำงานได้ตามคาด แต่เราจะตรวจสอบได้อย่างไรว่าข้อมูลจริงๆ เก็บใน Database? เราสามารถใช้แอปชื่อ MongoDB Realm Studio ซึ่งผ่านมันเราสามารถดูข้อมูลที่เก็บใน Realm Database ของ Simulator
สังเกตว่า วิธีนี้ทำงานได้เฉพาะเมื่อทดสอบแอปด้วย iOS Simulator
ในเมธอด viewDidLoad() เพิ่มบรรทัดโค้ดด้านล่าง ซึ่งจะพิมพ์ Real File Path ของแอปเรา:
print(realmDB.configuration.fileURL!)
ตอนนี้ Copy File Path ที่พิมพ์ใน Console เปิด Terminal รันคำสั่ง:
open REALM_FILE_PATH_HERE
ตรวจสอบให้แน่ใจว่าคุณดาวน์โหลด MongoDB Realm Studio จาก Browser ก่อนรันคำสั่งข้างต้น
ตอนนี้มันจะเปิด RealmFile ของแอปใน MongoDB Realm Studio จะแสดงข้อมูลที่เก็บใน Database ในรูปแบบตาราง
ถ้าคุณแก้ไขหรือลบ Task การเปลี่ยนแปลงจะสะท้อนในแอป MongoDB Realm Studio:
ยินดีด้วย! คุณสร้างแอปง่ายๆ ที่ Implement CRUD Operations ในแอป iOS แล้ว