我有一个类似于待办事项列表的简单应用程序。我使用TableViewController
,我能够为每行设置复选标记附件类型,还找到了一种保存行数据的方法,以便当应用程序重新启动时再次显示项目列表。
我想保存所有行的复选标记状态。我在Stack Overflow中尝试了其他查询,其中大多数都过时了。
这是我的应用程序代码
class ViewController: UITableViewController {
var shoppingList = [ShoppingList]()
override func viewDidLoad() {
super.viewDidLoad()
title = "Shopping List"
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addTapped))
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareTapped))
let clearList = UIBarButtonItem(title: "Clear List", style: .plain, target: self, action: #selector(clearList))
toolbarItems = [clearList]
navigationController?.isToolbarHidden = false
load()
tableView.tableFooterView = UIView() // clears the unused seperator lines
}
@objc func clearList() {
shoppingList.removeAll(keepingCapacity: true)
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
shoppingList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Word", for: indexPath)
cell.textLabel?.text = shoppingList[indexPath.row].itemName
cell.accessoryType = shoppingList[indexPath.row].checkmarkState ? .checkmark : .none
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
shoppingList.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCell.AccessoryType.checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.none
shoppingList[indexPath.row].checkmarkState = false
} else {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.checkmark
shoppingList[indexPath.row].checkmarkState = true
}
save()
}
@objc func addTapped() {
let ac = UIAlertController(title: "New Shopping Item", message: nil, preferredStyle: .alert)
ac.addTextField()
let addAction = UIAlertAction(title: "Add", style: .default) {
[weak self, weak ac] _ in
guard let item = ac?.textFields?[0].text else { return }
self?.addItem(item)
}
ac.addAction(addAction)
ac.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(ac, animated: true)
}
@objc func shareTapped() {
}
func addItem(_ item: String) {
let itemCapitalised = item.capitalized
shoppingList.insert(ShoppingList(itemName: itemCapitalised), at: 0)
let indexPath = IndexPath(row: 0, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
save()
}
func showErrorMessage(errorTitle: String, errorMessage: String) {
let ac = UIAlertController(title: errorTitle, message: errorMessage, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Ok", style: .default))
present(ac, animated: true)
}
func save() {
let jsonEncoder = JSONEncoder()
if let savedData = try? jsonEncoder.encode(shoppingList) {
let defaults = UserDefaults.standard
defaults.set(savedData, forKey: "shoppingList")
} else {
print("Failed to save people.")
}
}
func load() {
let defaults = UserDefaults.standard
if let savedList = defaults.object(forKey: "shoppingList") as? Data {
let jsonDecoder = JSONDecoder()
do {
shoppingList = try jsonDecoder.decode([ShoppingList].self, from: savedList)
} catch {
print("Failed to load List")
}
}
}
}
由于您已经在模型中存储了checkmarkState
,只需在tableView(_:cellForRowAt:)
中添加cell.accessoryType = shoppingList[indexPath.row].checkmarkState ? .checkmark : .none
以呈现复选标记状态。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Word", for: indexPath)
cell.textLabel?.text = shoppingList[indexPath.row].itemName
cell.accessoryType = shoppingList[indexPath.row].checkmarkState ? .checkmark : .none
return cell
}
还有一种更好的方法来编写tableView(_:didSelectRowAt:)
:只需反转checkmarkState
,然后重新加载行。
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
shoppingList[indexPath.row].checkmarkState = !shoppingList[indexPath.row].checkmarkState
tableView.reloadRows(at: [indexPath], with: .automatic)
save()
}
尽量记住MVC的理念。永远不要通过UI视图来确定模型的状态。仅由模型确定UI视图的状态。当您接收到用户输入时,直接更改模型,然后相应地重新呈现视图。保持模型作为真理的单一来源。