iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 23
0
Software Development

無中生有-從SWIFT語法學習到iOS APP的開發系列 第 23

Day23 - 建立 *.txt 檔案存取資料

前言

昨天因為高人指點,發現 UserDefaults 使用上沒有瑕疵啊~~~一切的一切都是自己 code 寫錯了...那是 bug 並不是 UserDefault 的錯啊!(解法在最下面)

不管,今天還是把 UserDefaults 改寫成用 *.txt 檔案來存取陣列

1.建立檔案

我們要再使用者開始選擇飲料之前,就先創建檔案了,所以要在 drinkViewController.swift 中,於 viewDidLoad() 中加入 code (為了複習昨天的教學,我這邊故意將檔案設定成不備份)

let fileManager = FileManager.default
    let TeaNameFile = NSHomeDirectory() + "/Documents/TeaName.txt"
    let TeaCountFile = NSHomeDirectory() + "/Documents/TeaCount.txt"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //創建檔案
        fileManager.createFile(atPath: TeaNameFile, contents: nil, attributes: nil)
        fileManager.createFile(atPath: TeaCountFile, contents: nil, attributes: nil)

        //設定URL
        var TeaNameFileURL = URL(fileURLWithPath: TeaNameFile)
        var TeaCountFileURL = URL(fileURLWithPath: TeaCountFile)
        
        do {
            var noBackUp = URLResourceValues()
            noBackUp.isExcludedFromBackup = true
            try TeaNameFileURL.setResourceValues(noBackUp)
            try TeaCountFileURL.setResourceValues(noBackUp)
        } catch {
            print("noBackUp setting fail")
        }
        
    }

這邊一個重點,就是要善用 do cath 來除錯,避免自己創建檔案失敗,造成後續程式崩潰

我舉我自己的例子,我在設定 TeaCountFile 的檔案路徑時,不小心 key 成 NSHomeDirectory() + "/Doucuments/TeaCount.txt"!

乍看之下好像沒錯,但是昨天說過,App 安裝時,系統設定備份的資料夾路徑是固定的,所以我不能自己創建一個 Doucuments 的資料夾 (Do'u'cuments),多了一個 'u',這裡 do catch 就幫我找到錯誤,也因此所以我可以在程式執行後就立馬獲得 "noBackup setting fail"

2.save button 設定寫入資料

判別式不變,重點是最後的 selectTeaName 和 selecTeaCount 要存入檔案

這邊又一個重點,能寫入檔案的陣列只有 NSArray,所以我們要先轉型成 NSArray 才能存入檔案

@IBAction func saveOrder(_ sender: UIBarButtonItem) {
        
        teaList.forEach { teaList in
            if teaList.value > 0 {
                if let i = selecTeaName.index(of: teaList.key) {
                    selecTeaCount[i] = teaList.value
                } else {
                    selecTeaName.append(teaList.key)
                    selecTeaCount.append(teaList.value)
                }
            } else {
                if let i = selecTeaName.index(of: teaList.key) {
                    selecTeaName.remove(at: i)
                    selecTeaCount.remove(at: i)
                }
            }
        }
        (selecTeaName as NSArray).write(toFile: TeaNameFile, atomically:true)
        (selecTeaCount as NSArray).write(toFile: TeaCountFile, atomically:true)
}

3.顯示訂購資料

來到 ShoppingCartViewController.swift

這邊的關鍵有兩個

  1. 要把檔案裡的 NSArray 轉回可讀的陣列
    swift 在這方面兼容了 OC 中的 NSArray,可以直接進行轉換。
    可以參考下面連結

Array 轉換

  1. 資料要在 view appear 裡就讀取
    至於要放在 DidAppear 還是 WillAppear 都可以,反正就是不能寫在 DidLoad 裡
    override func viewWillAppear(_ animated: Bool) {        
            if let NSCartName = NSArray(contentsOfFile: TeaNameFile) {
                if let NSCartCount = NSArray(contentsOfFile: TeaCountFile) {
                    shoppingCartName = NSCartName as! [String]
                    shoppingCartCount = NSCartCount as! [Int]
                }
            }
            shoppingTableView.reloadData()
    }

完成結果如下!!

最後,能訂購當然能取消

在左上角的「垃圾桶」右鍵藍線拖曳進 drinkViewController.swift 中,並加入清空表單

    @IBAction func removeOrder(_ sender: UIBarButtonItem) {
        teaList = ["茉莉綠茶": 0, "阿薩姆紅茶": 0, "四季春茶": 0, "黃金烏龍": 0, "微檸檬 紅/青": 0, "檸檬 綠/青": 0, "梅果綠": 0, "8冰綠": 0, "養樂多綠": 0, "蜂蜜綠": 0, "芒果青": 0, "冰淇淋紅茶": 0, "鮮柚綠": 0, "波霸 紅/綠/青/烏": 0, "波霸奶茶(大顆)": 0, "波霸奶綠(大顆)": 0, "珍珠 紅/綠/青/烏": 0, "珍珠奶茶(小顆)": 0, "珍珠奶綠(小顆)": 0, "椰果奶茶": 0, "仙草奶凍": 0, "鮮柚汁(季節限定)": 0]
        teaName = []
        Count = []
        selecTeaName = []
        selecTeaCount = []
        (selecTeaName as NSArray).write(toFile: TeaNameFile, atomically:true)
        (selecTeaCount as NSArray).write(toFile: TeaCountFile, atomically:true)
        teaTableView.reloadData()
    }

但是這邊發生一個小 bug,就是 Stepper 的數值不會歸零,當我按下"垃圾桶"的時候,訂購數量都歸零了,但是重新點按 Stepper 會延續之前的數量繼續計數..

所以我們有幾個地方要改

  1. 把 UIStepper 元件右鍵藍線拖曳進 DrinkTableViewCell.swift,但是是設定為 IBOutlet
@IBOutlet var stepper: UIStepper!
  1. 在原本的 Stepper @IBAction 加入判斷
@IBAction func teaCountStepper(value sender: UIStepper) {
        if stepper.value == 0 {
            sender.value = stepper.value
        }
        // ...程式碼略
    }
  1. 回到 drinkViewController.swift 中 ,在 tableView( cellForRowAt indexPath: IndexPath) -> UITableViewCell 裡加入一個判斷
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "drinkCell", for: indexPath) as! DrinkTableViewCell
        
        if Count[indexPath.row] == 0 {
            cell.stepper.value = Double(Count[indexPath.row])
        }
        // ...程式碼略
        return cell
    }

完成,結案!

後記

我也想結案啊~~但是我還有幾個想法想要加入啊~~

1.價格還沒計算
2.糖冰還沒選
3.大小杯也還沒選
4.購物車不能重新編輯數量(糖、冰)


上一篇
Day22 - 檔案管理
下一篇
Day24 - 鑲嵌 Collection View 進 Table View
系列文
無中生有-從SWIFT語法學習到iOS APP的開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言