iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 14
1
Software Development

iOS 三十天上架記帳 APP系列 第 14

Money Mom - 加入 Core Data 儲存記帳資訊

我們有了基本的新增、顯示界面,但還沒有實做任何和資料庫有關的邏輯,也因此目前程式沒辦法保留使用者儲存的資料,所以我們現在要加入 Core Data,用以儲存使用者新增的快速記帳。

設定 Core Data 基本架構

var persistentContainer: NSPersistentContainer?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // ...略

    let container = NSPersistentContainer(name: "Model")
    container.loadPersistentStores { description, error in
        guard error == nil else {
            fatalError("Failed to load store: Model")
        }

        self.persistentContainer = container
    }

    return true
}
import Foundation
import CoreData

public class QuickRecord: NSManagedObject {
    public class func fetchRequest() -> NSFetchRequest<QuickRecord> {
        return NSFetchRequest<QuickRecord>(entityName: "QuickRecord")
    }

    @NSManaged public var amount: String
    @NSManaged public var audioUUID: UUID
    @NSManaged public var id: UUID
    @NSManaged public var tags: Set<String>
    @NSManaged public var created_at: Date
}

修改原有程式碼邏輯

移除原本用 Delegate 實做的方法,因為 Core Data 導入之後,一切都以 Core Data 為核心,我們不再需要運用 Delegate 模式來傳遞新增的資料。

@objc func save() {
    let viewContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer!.viewContext

    guard let quickRecord = NSEntityDescription.insertNewObject(forEntityName: "QuickRecord", into: viewContext) as? QuickRecord else {
        fatalError("Insert QuickRecord Failed")
    }

    quickRecord.id = UUID()
    quickRecord.audioUUID = audioUUID
    quickRecord.tags = tags
    quickRecord.amount = amountTextField.text ?? "0"
    quickRecord.created_at = Date()

    try! viewContext.save()

    navigationController?.popViewController(animated: true)
}

利用 NSFetchedResultsController 來監控資料的修改

Apple 相當相當貼心地提供我們 NSFetchedResultsController,讓我們就可以透過設定 NSFetchRequest 及 ManagedObjectContext 輕易地達到監控資料改變的功能。

lazy var fetchedResultsController: NSFetchedResultsController<QuickRecord> = {
    let request = NSFetchRequest<QuickRecord>(entityName: "QuickRecord")
    request.sortDescriptors = [NSSortDescriptor(key: "created_at", ascending: false)]
    let viewContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer!.viewContext
    let fetchedResultsController = NSFetchedResultsController<QuickRecord>(fetchRequest: request, managedObjectContext: viewContext, sectionNameKeyPath: nil, cacheName: nil)
    fetchedResultsController.delegate = self

    return fetchedResultsController
}()

我們可以在 View 出現後,請 NSFetchedResultsController 幫我們抓好資料,然後再請 TableView 幫我們更新界面,超級方便啊!

override func viewDidLoad() {
    super.viewDidLoad()

    // ...略

    try! fetchedResultsController.performFetch()
}
extension HomeViewController: NSFetchedResultsControllerDelegate {
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        quickRecordTableView.reloadData()
    }
}
extension HomeViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        guard let quickRecords = fetchedResultsController.fetchedObjects else {
            return 0
        }

        return quickRecords.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = (tableView as! QuickRecordTableView).dequeueReusableCell(for: indexPath)

        cell.quickRecord = fetchedResultsController.object(at: indexPath)

        return cell
    }
}

展示

iOS 經常遇到資料更改後,界面也要跟著更新的需求,有點相似 React 配合 Redux 服用的模式,而在 iOS 中,Core Data 提供的相關功能,可以讓我們輕易地實做這樣的功能。

至此界面如下:

程式碼:GitHub

Core Data 完成後,不管能不能成功,先送審再說。


上一篇
Money Mom - 回顧、整理、前瞻
下一篇
Money Mom - 第二波攻勢號角響起
系列文
iOS 三十天上架記帳 APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言