【iOS】#20 記帳APP Part2: 計算機功能
小數點處理、NSExpression、Delegate傳值
本篇提及功能:
浮點數小數點處理
使用 NSExpression 讓字串進行運算
Delegate 傳值到其他元件
在記帳軟體中,會需要對記帳的金額做簡單的加減運算,所以需要計算機的功能
剛好記得 Peter 出的作業有包含到計算機,所以這次就把這部分遇到的問題記錄下來
APP wireframe
這部分功能的流程如下圖
第一頁是首頁,上方呈現前七日日期,下方有個面板呈現該日日期所有的記帳項目。按日期會切換顯示
第一頁下方會呈現當月總花費金額,以及新增記帳項目的按鈕
在第一頁上按記帳項目或者新增按鈕都會切換到第二頁記帳畫面。不同的是若是按記帳項目切換的話,會把該筆項目的資料一併傳到記帳畫面中,讓使用者進行修改
APP 實作
浮點數小數點處理
在 APP 中金錢花費的部分我採用的型別不是 Int 而是 Float,考量到彈性的問題所以這樣設定
不過使用 Float 的時候會遇到一些問題,比如說 let num: Float= 1 時,轉成 String 會呈現出 1.0,如果不想要這個 .0 呈現出來,就要轉換一下
extension Float { var trimAndStringify: String {
return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
}}
所以我用 extension 擴充 Float,truncatingRemainder 是取餘數,跟 % 功能一樣,但是在 Swift 上浮點數的取餘要使用 truncatingRemainder,否則會出錯
使用 NSExpression 讓字串進行運算
在計算機上會輸入運算符號,如何將整個字串進行運算,就需要使用 NSExpression
let expression = NSExpression(format: costTextField.text!)let double = expression.expressionValue(with: nil, context: nil) as! Doublelet float = Float(double)costTextField.text = float.trimAndStringify
把要執行運算的字串,傳入 NSExpression 的 format 參數中
let expression = NSExpression(format: costTextField.text!)
呼叫 expressionValue 並轉成 Double,記得這邊要轉成精度比較高的 Double ,否則進行浮點運算時會出錯
let double = expression.expressionValue(with: nil, context: nil) as! Double
最後兩行則是我轉成 Float 型別,並且做字串小數點的處理~
Delegate 傳值到其他元件
Swift 中傳值的方式有好幾種,包含 Segue、Notification、Closure等,之前我常用的是 Notification
但我發現 Notification 雖然可以讓呼叫其他元件的 function,但是傳值的部分比較不方便,因為它的參數型態規定是字典,傳回去的時候還需要做額外的處理
所以這次我使用 Delegate 傳值。以下呈現的是在第二頁 (CalculatorViewController)時,點選記帳類別的按鈕(CategoryBtnUIView),去改變 CalculatorViewController 記錄的記帳類別
- 在 CategoryBtnUIView 中定義 Protocol
protocol CategoryBtnUIViewDelegate: AnyObject { func changeCategory(category: Category)}
- 在 CategoryBtnUIView 中宣告 delegate 變數(之後把delegate指定給 CalculatorViewController)
weak var delegate: CategoryBtnUIViewDelegate?
- 在 CategoryBtnUIView 的按鈕上,說明按下後 delegate 要做的事情
@objc func touchAction() { delegate?.changeCategory(category: category)}
- 在 CalculatorViewController 中,設定代理
class CalculatorViewController: UIViewController, CategoryBtnUIViewDelegate { ...
- 在 CalculatorViewController 中實作代理的協定內容
func changeCategory(category: Category) { // spendInfo是Calculator中的變數,記錄有關此筆記帳的內容
spendInfo.category = category}
- 在 CalculatorViewController 生成 CategoryBtnUIView 的地方,把 delegate 設定成自己(CalculatorViewController)
let categoryView = CategoryBtnUIView(category: categoryCase)categoryView.delegate = self
APP Demo
後記
下次會做記帳資料 CRUD 的部分。目前資料是存在 Firebase 中,本來想用看看 AirTable 不過想說 Firebase 有整合 Auth 以及 DB,所以還是選了 Firebase