I’m a little closer, but my items that cost $50 or less do not appear on my screen correctly, and it crashes…
First, my changes:
ItemStore.swift:
var over50Items = [Item]()
var under50Items = [Item]()
@discardableResult func createItem() -> Item {
let newItem = Item(random: true)
if newItem.valueInDollars > 50 {
over50Items.append(newItem)
} else {
under50Items.append(newItem)
}
return newItem
}
func removeItem(_ item: Item) {
if let index = over50Items.firstIndex(of: item) {
over50Items.remove(at: index)
} else if let index = under50Items.firstIndex(of: item){
under50Items.remove(at: index)
}
}
// Listing 9.21 p 209 - Reordering items within the store
func moveItem(from fromIndex: Int, to toIndex: Int) {
if fromIndex == toIndex {
return
}
// Get reference to object being moved so you can reinsert it
let movedOver50Item = over50Items[fromIndex]
// Remove item from array
over50Items.remove(at: fromIndex)
// insert item in array at new location
over50Items.insert(movedOver50Item, at: toIndex)
let movedUnder50Items = under50Items[fromIndex]
under50Items.remove(at: fromIndex)
under50Items.insert(movedUnder50Items, at: toIndex)
}
}
Changes to ItemViewController.swift
class ItemsViewController : UITableViewController{
var itemStore: ItemStore!
let sections = ["Over $50","$50 or Less"]
@IBAction func addNewItem(_ sender: UIButton) {
// Listing 9.15 p 205
// Make a new index path for the 0th section, last row
/* this crashes the app
let lastRow = tableView.numberOfRows(inSection: 0)
let indexPath = IndexPath(row: lastRow, section: 0)
*/
// Create a new item and add it to the store
let newItem = itemStore.createItem()
// Figure out where that item is in the array
if let index = itemStore.over50Items.firstIndex(of: newItem) {
let indexPath = IndexPath(row: index, section: 0)
// Insert this new row into the table
tableView.insertRows(at: [indexPath], with: .automatic)
print("Item Name: \(newItem.name)")
print("Value: \(newItem.valueInDollars)")
} else if let index = itemStore.under50Items.firstIndex(of: newItem) {
let indexPath = IndexPath(row: index, section: 1)
tableView.insertRows(at: [indexPath], with: .automatic)
// console stuff
print("Item Name: \(newItem.name)")
print("Value: $\(newItem.valueInDollars)")
}
…
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return itemStore.over50Items.count
} else {
return itemStore.under50Items.count
}
…
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// better yet, get a new or recycled cell
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
// Set the text on the cell with the description of the item
// that is at the nth index of items, where n = row this cell
// will appear in on the table view
if itemStore.over50Items.firstIndex(of: itemStore.over50Items[indexPath.row]) != nil {
cell.textLabel?.text = itemStore.over50Items[indexPath.row].name
cell.detailTextLabel?.text = "$\(itemStore.over50Items[indexPath.row].valueInDollars)"
return cell
} else {
cell.textLabel?.text = itemStore.under50Items[indexPath.row].name
cell.detailTextLabel?.text = "$\(itemStore.under50Items[indexPath.row].valueInDollars)"
return cell
}
}
// Listing 9.20 p 208 - Implementing table view row deletion
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
// If the table view is asking to commit a delete command...
if editingStyle == .delete {
if itemStore.over50Items.firstIndex(of: itemStore.over50Items[indexPath.row]) != nil {
// remove the item from the store
itemStore.removeItem(itemStore.over50Items[indexPath.row])
// Also remove that row from the table view with an animation
tableView.deleteRows(at: [indexPath], with: .automatic)
} else {
itemStore.removeItem(itemStore.under50Items[indexPath.row])
// Also remove that row from the table view with an animation
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
}
// listing 9.22 p 209 Implementing table view row reodering
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// update the model
itemStore.moveItem(from: sourceIndexPath.row, to: destinationIndexPath.row)
}
// Create a standard header that includes the returned text.
override func tableView(_ tableView: UITableView, titleForHeaderInSection
section: Int) -> String? {
if section == 0 {
return sections[0]
} else {
return sections[1]
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
Output:
…
Console:
Item Name: Fluffy Bear
Value: 89
Item Name: Rusty Bear
Value: $25
Fatal error: Index out of range
2020-06-20 14:43:57.162940-0400 LootLogger[27239:2242833] Fatal error: Index out of range
(lldb)
Notice that the console displays the correct second item, while the first item duplicates
on screen in the second section.