我正在尝试使用CoreData在iOS应用程序的表格视图中显示旅程的时间戳和距离。
我已遵循本教程:https://cocoacasts.com/populate-a-table-view-with-nsfetchedresultscontroller-and-swift-3/,但未能成功构建我的应用。
不确定到底为什么现在不起作用,是日期存储的时间戳记格式和/或旅程距离的存储布尔值吗?
class SavedJourneysViewController: UIViewController {
// HENRY: -
@IBOutlet var tableView: UITableView!
// HENRY: -
private let persistentContainer = NSPersistentContainer(name: "Journeys")
// HENRY: -
fileprivate lazy var fetchedResultsController: NSFetchedResultsController<Journey> = {
// Create Fetch Request
let fetchRequest: NSFetchRequest<Journey> = Journey.fetchRequest()
// Configure Fetch Request
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Journey.timestamp), ascending: true)]
// Create Fetched Results Controller
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.persistentContainer.viewContext, sectionNameKeyPath: #keyPath(Journey.distance), cacheName: nil)
// Configure Fetched Results Controller
fetchedResultsController.delegate = self
return fetchedResultsController
}()
// HENRY: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
title = "Journeys"
persistentContainer.loadPersistentStores { (persistentStoreDescription, error) in
if let error = error {
print("Unable to Load Persistent Store")
print("\(error), \(error.localizedDescription)")
} else {
self.setupView()
do {
try self.fetchedResultsController.performFetch()
} catch {
let fetchError = error as NSError
print("Unable to Perform Fetch Request")
print("\(fetchError), \(fetchError.localizedDescription)")
}
self.updateView()
}
}
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(_:)), name: Notification.Name.UIApplicationDidEnterBackground, object: nil)
}
// HENRY: - Navigation
// REMOVED
// HENRY: - View Methods
private func setupView() {
updateView()
}
fileprivate func updateView() {
var hasJourneys = false
if let journeys = fetchedResultsController.fetchedObjects {
hasJourneys = journeys.count > 0
}
tableView.isHidden = !hasJourneys
}
// HENRY: - Notification Handling
@objc func applicationDidEnterBackground(_ notification: Notification) {
do {
try persistentContainer.viewContext.save()
} catch {
print("Unable to Save Changes")
print("\(error), \(error.localizedDescription)")
}
}
}
extension SavedJourneysViewController: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
updateView()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch (type) {
case .insert:
if let indexPath = newIndexPath {
tableView.insertRows(at: [indexPath], with: .fade)
}
break;
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
break;
case .update:
if let indexPath = indexPath, let cell = tableView.cellForRow(at: indexPath) as? JourneyTableViewCell {
configure(cell, at: indexPath)
}
break;
case .move:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath], with: .fade)
}
break;
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
case .delete:
tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
default:
break;
}
}
}
extension SavedJourneysViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
guard let sections = fetchedResultsController.sections else { return 0 }
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sectionInfo = fetchedResultsController.sections?[section] else { fatalError("Unexpected Section") }
return sectionInfo.numberOfObjects
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard let sectionInfo = fetchedResultsController.sections?[section] else { fatalError("Unexpected Section") }
return sectionInfo.name
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: JourneyTableViewCell.reuseIdentifier, for: indexPath) as? JourneyTableViewCell else {
fatalError("Unexpected Index Path")
}
// Configure Cell
configure(cell, at: indexPath)
return cell
}
func configure(_ cell: JourneyTableViewCell, at indexPath: IndexPath) {
// Fetch Journey
let journey = fetchedResultsController.object(at: indexPath)
// Configure Cell
cell.dateLabel.text = journey.timestamp
cell.distanceLabel.text = journey.distance
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Fetch Quote
let journey = fetchedResultsController.object(at: indexPath)
// Delete Quote
journey.managedObjectContext?.delete(journey)
}
}
}
extension SavedJourneysViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}