Hands-On Full:Stack Development with Swift
上QQ阅读APP看书,第一时间看更新

Loading and auto-saving the Shopping List

Now that we have the app working the way we want, there is one thing missing: the app doesn't save our Shopping List every time we make changes to our list. Also, we do not want to show the fake items. So let's see how we can persist the Shopping List and save it every time we make changes. For this we will need to:

  1. Switch to Item.swift and first import the core Foundation framework as we will be using UserDefaults , PropertyListEncoder, and PropertyListDecoder class objects to save our items. Add the following line to the top of the file:
import Foundation
  1. Have the Item class implement the Codable protocol, which will allow our item to be encoded and decoded to be stored in UserDefaults. UserDefaults is a quick and easy way to save user settings or data that is application-specific:
class Item: Codable {
  1. Add a new instance method called toggleCheck, which will return a new item with the same name, but with its isChecked value toggled. We will use this new item and update our item in the Table View Controller with this new item rather than mutating the item itself:
func toggleCheck() -> Item {
return Item(name: name, isChecked: !isChecked)
}
  1. Use extensions in Swift to extend the Array class to add a save method and a class level load method to save and load the items from UserDefaults:
extension Array where Element == Item {
func save() {
let data = try? PropertyListEncoder().encode(self)
UserDefaults.standard.set(data, forKey: String(describing:
Element.self))
UserDefaults.standard.synchronize()
}

static func load() -> [Element] {
if let data = UserDefaults.standard.value(forKey:
String(describing: Element.self)) as? Data,
let items = try? PropertyListDecoder().decode([Element].self,
from: data){
return items
}

return []
}
}
  1. Switch to the ItemTableViewController file and update the items instance variable that is defaulting to fake items, to actually load from UserDefaults. We can do so by updating it to this:
var items: [Item] = [Item].load() {
didSet {
items.save()
}
}
  1. In the preceding code block, we are setting items array to default to items loaded from the UserDefaults storage. This is done by calling [Item].load(). We also have a didSet block defined that gets called every time the items array is modified. We need to save the items to UserDefaults again when that happens by calling the save method on the items array.
  2. Update the tableView(_:didSelectRowAt:) method again and replace it with this and use the toggleCheck method that we just created instead to trigger the didSet method to automatically save our items:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
items[indexPath.row] = items[indexPath.row].toggleCheck()
tableView.reloadRows(at: [indexPath], with: .middle)
}

Let's run the app now and you should not see any items at first but if you add few items, check some items, close the app, and start it up again, you will see the items will load in the state they were before closing the app.