forked from bignerdranch/CoreDataStack
/
BooksTableViewController.swift
149 lines (112 loc) · 4.81 KB
/
BooksTableViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//
// BooksTableViewController.swift
// CoreDataStack
//
// Created by Robert Edwards on 11/23/15.
// Copyright © 2015-2016 Big Nerd Ranch. All rights reserved.
//
import UIKit
import CoreDataStack
import CoreData
// swiftlint:disable weak_delegate (False positive)
class BooksTableViewController: UITableViewController {
private var stack: CoreDataStack!
private lazy var fetchedResultsController: FetchedResultsController<Book> = {
let fetchRequest = NSFetchRequest<Book>(entityName: Book.entityName)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)]
let frc = FetchedResultsController<Book>(fetchRequest: fetchRequest,
managedObjectContext: self.stack.mainQueueContext,
sectionNameKeyPath: "firstInitial")
frc.setDelegate(self.frcDelegate)
return frc
}()
private lazy var frcDelegate: BooksFetchedResultsControllerDelegate = {
return BooksFetchedResultsControllerDelegate(tableView: self.tableView)
}()
// MARK: - Lifecycle
init(coreDataStack stack: CoreDataStack) {
super.init(nibName: nil, bundle: nil)
self.stack = stack
}
required init?(coder aDecoder: NSCoder) {
preconditionFailure("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "GenericReuseCell")
do {
try fetchedResultsController.performFetch()
} catch {
print("Failed to fetch objects: \(error)")
}
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done,
target: self,
action: #selector(close))
}
// MARK: - Actions
@objc private func close() {
dismiss(animated: true, completion: nil)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController.sectionCount
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController.sections?[section].objects.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GenericReuseCell") ?? UITableViewCell()
guard let sections = fetchedResultsController.sections else {
assertionFailure("Sections missing")
return cell
}
let section = sections[indexPath.section]
let book = section.objects[indexPath.row]
cell.textLabel?.text = book.title
return cell
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return fetchedResultsController.sections?[section].indexTitle
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return fetchedResultsController.sections?.map() { $0.indexTitle ?? "" }
}
}
class BooksFetchedResultsControllerDelegate: FetchedResultsControllerDelegate {
private weak var tableView: UITableView?
// MARK: - Lifecycle
init(tableView: UITableView) {
self.tableView = tableView
}
func fetchedResultsControllerDidPerformFetch(_ controller: FetchedResultsController<Book>) {
tableView?.reloadData()
}
func fetchedResultsControllerWillChangeContent(_ controller: FetchedResultsController<Book>) {
tableView?.beginUpdates()
}
func fetchedResultsControllerDidChangeContent(_ controller: FetchedResultsController<Book>) {
tableView?.endUpdates()
}
func fetchedResultsController(_ controller: FetchedResultsController<Book>,
didChangeObject change: FetchedResultsObjectChange<Book>) {
switch change {
case let .insert(_, indexPath):
tableView?.insertRows(at: [indexPath], with: .automatic)
case let .delete(_, indexPath):
tableView?.deleteRows(at: [indexPath], with: .automatic)
case let .move(_, fromIndexPath, toIndexPath):
tableView?.moveRow(at: fromIndexPath, to: toIndexPath)
case let .update(_, indexPath):
tableView?.reloadRows(at: [indexPath], with: .automatic)
}
}
func fetchedResultsController(_ controller: FetchedResultsController<Book>,
didChangeSection change: FetchedResultsSectionChange<Book>) {
switch change {
case let .insert(_, index):
tableView?.insertSections(IndexSet(integer: index), with: .automatic)
case let .delete(_, index):
tableView?.deleteSections(IndexSet(integer: index), with: .automatic)
}
}
}