我們今天先從 MainView 來做教學,之前學過的功能我就簡單帶過讓各位可以做練習
我們透過前面設定好的架構我們已經有了 MainView 的 Controller 以及 tableViewCell 了
接下來我們一個接一個帶大家完成!
在接下來介紹時我不會完整的貼整個程式碼,而是專注於介紹新的程式碼用途!
透過前面的設定應該大家不會有什麼問題,資料庫套件記得也要 import 喔!
import UIKit
import RealmSwift
import UserNotifications
按照前面設定的要求我們設定一個 tableView 來顯示!
別忘記要從 xib 拉元件過來 swift 設定喔!
    @IBOutlet weak var tableView: UITableView!
接著同樣我們需要設定一個變數來儲存資料
    var alarms: [AlarmData] = []
別忘了要記得設定 tableView 的代理跟 tableView 的註冊
    func setUI() {
        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(UINib(nibName: "MainTableViewCell", 
                                 bundle: nil), 
                           forCellReuseIdentifier: "MainTableViewCell")
    }
我們要設定一個 @objc 用來處理每個鬧鐘開關狀態改變的事件
    @objc func alarmSwitchChange(_ sender: UISwitch) {
        let index = sender.tag
        let realm = try! Realm()
        try! realm.write {
            alarms[index].isEnabled = sender.isOn
        }
    }
    // 載入鬧鐘資料
    func loadAlarms() {
        let realm = try! Realm()
        // 取得所有鬧鐘資料並按時間排序
        alarms = Array(realm.objects(AlarmData.self).sorted(byKeyPath: "alarmTime", 
                                                            ascending: true))
        print("目前鬧鐘數量:", alarms.count)
        tableView.reloadData()
    }
    // 刪除鬧鐘
    func deleteAlarm(_ alarm: AlarmData, 
                     at indexPath: IndexPath) {
        let realm = try! Realm()
        // 刪除通知請求
        UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [alarm.creatTime])
        for index in 0..<7 {
            UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["\(alarm.creatTime)_\(index)"])
        }
        try! realm.write {
            realm.delete(alarm)
        }
        alarms.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .fade)
    }
        // enumerated 會返回一個包含索引和值的元組序列
        // compactMap 會過濾掉 nil 值並返回一個新的陣列
    func repeatDaysText(_ repeatDays: List<Bool>) -> String {
        let days = ["週日", "週一", "週二", "週三", "週四", "週五", "週六"]
        let arr = Array(repeatDays)
        let selected = arr.enumerated().compactMap { $0.element ? days[$0.offset] : nil }
        if arr == [false, true, true, true, true, true, false] {
            return "平日"
        } else if arr == [true, false, false, false, false, false, true] {
            return "週末"
        } else if arr.allSatisfy({ $0 }) {
            return "每天"
        } else {
            return selected.isEmpty ? "永不" : selected.joined(separator: "、")
        }
    }
比較複雜的 func 到這裡我在這邊帶各位做完啦~
剩下轉換時間制跟取得上下午的 func 讓大家自主練習看看!
我們需要特別寫一個 viewWillAppear 來做每當畫面刷新就重新讀一次資料
讓我們的畫面可以保持顯示最新資料
    // 每次畫面出現時重新載入鬧鐘資料
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        loadAlarms()
    }
首先設定的部分跟之前一樣就展示一下,不多做介紹
extension MainViewController: UITableViewDelegate, UITableViewDataSource {
    ...
}
接著我們來看程式碼內容
我們這次會用到
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell", for: indexPath) as! MainTableViewCell
        let alarm = alarms[indexPath.row]
        cell.lbTime.text = get12HourTime(alarm.alarmTime)
        cell.lbNoon.text = getNoon(alarm.alarmTime)
        let name = alarm.name.isEmpty ? "鬧鐘" : alarm.name
        let repeatText = repeatDaysText(alarm.repeatDays)
        cell.lbSubtitle.text = "\(name),\(repeatText)"
        cell.swAlarm.isOn = alarm.isEnabled
        cell.swAlarm.tag = indexPath.row
        cell.swAlarm.removeTarget(nil, action: nil, for: .allEvents)
        cell.swAlarm.addTarget(self, action: #selector(alarmSwitchChange(_:)), for: .valueChanged)
        cell.swAlarm.isHidden = isEditingMode
        return cell
    }
    
    
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let alarm = alarms[indexPath.row]
        let editAlarmVC = AddAlarmViewController(nibName: "AddAlarmViewController", bundle: nil)
        editAlarmVC.alarmToEdit = alarm
        editAlarmVC.selectedSound = alarm.sound
        editAlarmVC.delegate = self
        let navController = UINavigationController(rootViewController: editAlarmVC)
        self.present(navController, animated: true, completion: nil)
    }
    
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            let alarm = alarms[indexPath.row]
            deleteAlarm(alarm, at: indexPath)
        }
    }
    
    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(style: .destructive, title: "刪除") { [weak self] (_, _, completionHandler) in
            guard let self = self else { return }
            let alarm = self.alarms[indexPath.row]
            self.deleteAlarm(alarm, at: indexPath)
            completionHandler(true)
        }
        deleteAction.backgroundColor = .red
        return UISwipeActionsConfiguration(actions: [deleteAction])
    }
protocl 的部分我們就先給各位看程式碼
明天介紹 AddAlarmView 時再跟各位做講解 func
先知道我們要的功能有
在做了這些動作後需要重新刷新畫面上的鬧鐘顯示資料
這樣就很清楚了吧!
extension MainViewController: AlarmUpdateDelegate {
    func didAddNewAlarm() {
        print("didAddNewAlarm called")
        loadAlarms()
    }
    func didEditAlarm() {
        print("didEditAlarm called")
        loadAlarms()
    }
    func didDeleteAlarm() {
        print("didDeleteAlarm called")
        loadAlarms()
    }
}