I am trying to make headers for my tableview that are separated by date, which is a string. I am using core data and the NSFetchResultsController.
I am basically making an agenda which will separate events based on a string date.
I cannot find anywhere how to do this in swift 3.
My code is below:
import UIKit
import CoreData
class MainVC: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var segControl: UISegmentedControl!
var fetchedResultsController: NSFetchedResultsController<Event>!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
//generateTest()
attemptFetchRequest()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell", for: indexPath) as? EventCell {
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
return cell
}
return EventCell()
}
//calling configure cell in this VC too
func configureCell(cell: EventCell, indexPath: NSIndexPath) {
let event = fetchedResultsController.object(at: indexPath as IndexPath)
cell.configureCell(event: event)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let events = fetchedResultsController.fetchedObjects , events.count > 0 {
let event = events[indexPath.row]
performSegue(withIdentifier: "DetailsVC", sender: event)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "DetailsVC" {
if let dest = segue.destination as? DetailsVC {
if let event = sender as? Event {
dest.eventToEdit = event
}
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if let sections = fetchedResultsController.sections {
return sections.count
}
return 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let sections = fetchedResultsController.sections {
let sectionInfo = sections[section]
return sectionInfo.numberOfObjects
}
return 0
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
//no idea what to do here
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 126
}
func attemptFetchRequest() {
let fetchRequest: NSFetchRequest<Event> = Event.fetchRequest()
let dateSort = NSSortDescriptor(key: "date", ascending: false) //sort by date
let tagSort = NSSortDescriptor(key: "tag", ascending: false) //sort by tag
if segControl.selectedSegmentIndex == 0 {
fetchRequest.sortDescriptors = [dateSort]
} else {
fetchRequest.sortDescriptors = [tagSort]
}
let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = self
self.fetchedResultsController = controller
do {
try fetchedResultsController.performFetch()
} catch {
let err = error as NSError
print("\(err)")
}
}
}
As you can see I am sorting by date in my attemptFetch() func, but how do I split them up in the table view by date?
Thank you.
EDIT!!!
I sort of fixed it, The contents are saving into the correct sections however, every time i add or delete from tableview, the contents are not reloaded and when I press the segmented control, nothing happens.
I am reloading the table data so I'm not sure whats happening..
code:
import UIKit import CoreData
class MainVC: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var segControl: UISegmentedControl!
var fetchedResultsController: NSFetchedResultsController<Event>!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
//generateTest()
attemptFetchRequest()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell", for: indexPath) as? EventCell {
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
return cell
}
return EventCell()
}
//calling configure cell in this VC too
func configureCell(cell: EventCell, indexPath: NSIndexPath) {
let event = fetchedResultsController.object(at: indexPath as IndexPath)
cell.configureCell(event: event)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let events = fetchedResultsController.fetchedObjects , events.count > 0 {
let event = events[indexPath.row]
performSegue(withIdentifier: "DetailsVC", sender: event)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "DetailsVC" {
if let dest = segue.destination as? DetailsVC {
if let event = sender as? Event {
dest.eventToEdit = event
}
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if let sections = fetchedResultsController.sections {
return sections.count
}
return 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let sections = fetchedResultsController.sections {
let sectionInfo = sections[section]
return sectionInfo.numberOfObjects
}
return 0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 126
}
func attemptFetchRequest() {
let fetchRequest: NSFetchRequest<Event> = Event.fetchRequest()
let dateSort = NSSortDescriptor(key: "date", ascending: false) //sort by date
let tagSort = NSSortDescriptor(key: "tag", ascending: false) //sort by tag
if segControl.selectedSegmentIndex == 0 {
fetchRequest.sortDescriptors = [dateSort]
} else {
fetchRequest.sortDescriptors = [tagSort]
}
let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = self
self.fetchedResultsController = controller
do {
try fetchedResultsController.performFetch()
} catch {
let err = error as NSError
print("\(err)")
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
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 {
if let cell = tableView.cellForRow(at: indexPath) as? EventCell {
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
}
}
break
case.move:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
if let indexPath = newIndexPath {
tableView.insertRows(at: [indexPath], with: .fade)
}
break
}
}
func generateTest() {
let event = Event(context: context)
event.detail = "going to a meeting"
event.location = "san fran"
event.tag = "meeting"
event.title = "Google meeting"
let event2 = Event(context: context)
event2.detail = "going to a meeting"
event2.location = "LA"
event2.tag = "lunch"
event2.title = "lunch with musk"
let event3 = Event(context: context)
event3.detail = "going to a meeting"
event3.location = "Toronto"
event3.tag = "date"
event3.title = "visiting GF"
let event4 = Event(context: context)
event4.detail = "going to a meeting"
event4.location = "san fran"
event4.tag = "meeting"
event4.title = "Google meeting"
ad.saveContext()
}
@IBAction func segControllerChanged(_ sender: Any) {
attemptFetchRequest()
tableView.reloadData()
}
}
Thanks
You can use the sectionNameKeyPath to sort by a property for each section, and your NSFetchedResultsController
will return sections and objects to each fetched section accordingly, instead of returning fetched objects as without it, they will get ordered in sections that is.
You have it currently set to nil
.
The key path on the fetched objects used to determine the section they belong to.
It would be better if your stored your dates as Date
in Core Data as you may find that strings won't sort into correct date order.
You need to specify the sectionKeyPath
on your NSFetchedResultsController
func attemptFetchRequest() {
let fetchRequest: NSFetchRequest<Event> = Event.fetchRequest()
var key: String
let dateSort = NSSortDescriptor(key: "date", ascending: false) //sort by date
let tagSort = NSSortDescriptor(key: "tag", ascending: false) //sort by tag
if segControl.selectedSegmentIndex == 0 {
key = "date"
} else {
key = "tag"
}
let sort = NSSortDescriptor(key: key, ascending: false)
fetchRequest.sortDescriptors = [sort]
fetchRequest.sectionKeyPath = key
let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = self
self.fetchedResultsController = controller
do {
try fetchedResultsController.performFetch()
} catch {
let err = error as NSError
print("\(err)")
}
}
Then, you can use the NSFetchedResultsSectionInfo
to get the name of the section:
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let sectionInfo = self.fetchedResultsController.sections?[section]
return sectionInfo?.name ?? ""
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.