简体   繁体   中英

CoreData splitting sections by String

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 section​Name​Key​Path 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM