LucidDreams/FavoriteCreatureListViewController.swift
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Defines the `FavoriteCreatureListViewController` which displays a list |
of creatures. The user can pick their favorite creature from this |
view controller. This view controller is displayed when the favorite |
creature cell is tapped from the `DreamListViewController`. |
*/ |
import UIKit |
/** |
A view controller that displays a list of creatures to select as a user's |
favorite creature. |
*/ |
class FavoriteCreatureListViewController: UITableViewController { |
// MARK: Properties |
var favoriteCreatureDidChange: ((Dream.Creature) -> Void)? |
/* |
We only have one state property for this view controller so we won't create |
a wrapper struct for it. |
*/ |
private var favoriteCreature: Dream.Creature! |
/** |
Setter accessible to other view controllers. Only set this before the |
view controller's view has appeared. |
*/ |
func setFavoriteCreature(_ favoriteCreature: Dream.Creature) { |
self.favoriteCreature = favoriteCreature |
} |
/** |
This method takes in a closure that can modify the view controller's |
`favoriteCreature` property. |
Look at the call sites that use this method to get a better understanding |
of how the model is changed. |
The crux of this design is that after we mutate the favorite creature we |
perform a diff of the previous values and new value. Based on that diff |
we update our UI with the appropriate changes. |
This is a very nice aspect of this design approach because it centralizes |
our UI update code, preserving "Locality of Reasoning" for our UI (this |
is described in the WWDC session). |
*/ |
func withFavoriteCreature(_ mutateFavoriteCreature: (inout Dream.Creature) -> Void) { |
let old = favoriteCreature |
mutateFavoriteCreature(&favoriteCreature!) |
guard favoriteCreature != old else { |
// If the new and old are the same we just need to deselect the row. |
if let indexPathForSelectedRow = tableView.indexPathForSelectedRow { |
tableView.deselectRow(at: indexPathForSelectedRow, animated: true) |
} |
return |
} |
/* |
Perform the diff. Deselect the previously selected cell and select |
the recently tapped one. |
*/ |
tableView.beginUpdates() |
if let old = old { |
let indexOfPreviousFavoriteCreature = Dream.Creature.all.index(of: old)! |
let indexPathOfPreviousFavoriteCreature = IndexPath(row: indexOfPreviousFavoriteCreature, section: 0) |
tableView.deselectRow(at: indexPathOfPreviousFavoriteCreature, animated: true) |
let previousFavoriteCreatureCell = tableView.cellForRow(at: indexPathOfPreviousFavoriteCreature) |
previousFavoriteCreatureCell?.accessoryType = .none |
} |
let indexOfNewFavoriteCreature = Dream.Creature.all.index(of: favoriteCreature!)! |
let indexPathofNewFavoriteCreature = IndexPath(row: indexOfNewFavoriteCreature, section: 0) |
tableView.deselectRow(at: indexPathofNewFavoriteCreature, animated: true) |
let newFavoriteCreatureCell = tableView.cellForRow(at: indexPathofNewFavoriteCreature) |
newFavoriteCreatureCell?.accessoryType = .checkmark |
tableView.endUpdates() |
} |
// MARK: UITableViewDelegate & UITableViewDataSource |
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
return Dream.Creature.all.count |
} |
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) |
let creature = Dream.Creature.all[indexPath.row] |
if creature == favoriteCreature { |
cell.accessoryType = .checkmark |
} else { |
cell.accessoryType = .none |
} |
cell.imageView!.image = creature.image |
cell.textLabel!.text = creature.name |
return cell |
} |
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { |
withFavoriteCreature { newFavoriteCreature in |
newFavoriteCreature = Dream.Creature.all[indexPath.row] |
} |
} |
// MARK: IBActions |
@IBAction func cancelTapped() { |
dismiss(animated: true, completion: nil) |
} |
@IBAction func doneTapped() { |
favoriteCreatureDidChange?(favoriteCreature) |
dismiss(animated: true, completion: nil) |
} |
} |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-10-27