應用於時鐘 App 開啟世界時鐘或鬧鐘分頁都可以儲存每次新增修改的結果,即使關閉 App 重新開啟仍保留上次儲存結果。
- 透過型別方法寫鬧鐘型別 Alarm 的儲存 saveAlarm 和讀取 loadAlarms
- 型別須遵從
Codable
才可以編碼、解碼
【檔案位置】
static let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
編碼:自訂型別轉成 Data、解碼:Data 轉成自訂型別
- 自訂型別需要遵從 Codable 的 protocol:則可編碼、解碼
其中的 property 也需要遵從 Codable
// 編碼
let encoder = JSONEncoder()
let data = try? encoder.encode(alarms)// 解碼
let decoder = JSONDecoder()
return try? decoder.decode([Self].self, from: data)
資料儲存:存在 Containers 下的 Data 的 Documents Directory
// 存檔
let url = documentsDirectory.appendingPathComponent("alarm") // 路徑
try? data?.write(to: url) // 寫入// 讀取
let url = documentsDirectory.appendingPathComponent("alarm")
guard let data = try? Data(contentsOf: url) else { return nil }
【儲存】
// 自訂型別編碼後, 再寫入 documentDirectory
static func saveAlarm(_ alarms: [Alarm]) {
// 編碼
let encoder = JSONEncoder()
let data = try? encoder.encode(alarms)
// 存檔
let url = documentsDirectory.appendingPathComponent("alarm") // 路徑
try? data?.write(to: url) // 寫入
}
【讀取】
// 讀取 documentDirectory 再解碼成自訂型別
static func loadAlarms() -> [Self]? { // [Self]: Self (大寫的 S) 代表型別 Alarm
// 讀取
let url = documentsDirectory.appendingPathComponent("alarm")
guard let data = try? Data(contentsOf: url) else { return nil }
// 解碼
let decoder = JSONDecoder()
return try? decoder.decode([Self].self, from: data)
}
〖應用〗
偵測屬性變更的 property observer:didSet
使用的時機:想要將鬧鐘列表依鬧鐘時間排序
原來不需要特別將鬧鐘的 cell 重新排列,只需要對資料內容做設定。概念是透過偵測屬性變更的 property observer — didSet,只要當資料內容變動時不論新增、修改或刪除時會觸發排序,就可以讓資料內容永遠呈現有序狀態,自然而然鬧鐘列表就會依鬧鐘的時間排序。
var alarmList = [Alarm]() {
didSet {
alarmList = alarmList.sorted { $0.alarmTime < $1.alarmTime }
}
}
綜合自訂型別解碼編碼和資料儲存
Alarm.swift
// MARK: - 本地端資料儲存 Document directory
static let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! // 自訂型別編碼後,再寫入 documentDirectory
static func saveAlarm(_ alarms: [Alarm]) {
// 編碼
let encoder = JSONEncoder()
let data = try? encoder.encode(alarms)
// 存檔
let url = documentsDirectory.appendingPathComponent("alarm") // 路徑
try? data?.write(to: url) // 寫入
}// 讀取 documentDirectory 再解碼成自訂型別
static func loadAlarms() -> [Self]? { // [Self]: Self (大寫的 S) 代表型別 Alarm
// 讀取
let url = documentsDirectory.appendingPathComponent("alarm")
guard let data = try? Data(contentsOf: url) else { return nil }
// 解碼
let decoder = JSONDecoder()
return try? decoder.decode([Self].self, from: data)
}
AlarmTableViewController.swift
// 資料內容有變動時則儲存
var alarmList = [Alarm]() {
didSet {
alarmList = alarmList.sorted { $0.alarmTimeForDateFormatter < $1.alarmTimeForDateFormatter}
Alarm.saveAlarm(alarmList)
}
}// 鬧鐘分頁的開始畫面呼叫讀取鬧鐘內容
override func viewDidLoad() {
super.viewDidLoad()
if let alarmList = Alarm.loadAlarms(){
self.alarmList = alarmList
}
}