Displaying data in sections in a Table View using Core Data in Swift
As Wain has said, the FRC doesn't help much. An FRC has two main advantages, over and above an ordinary fetch: it can manage the sections for you, and it can automatically handle inserts/deletes/updates, via its delegate methods. The first is of no use in your case, since you want one section per Order. And the second is of little help since the FRC will watch only one Entity for changes, yet your table view is built from three.
Nevertheless, I think you might be able to use an FRC to some effect. First, do not bother with sectionNameKeyPath
: you have a one-one mapping between Orders
and table view sections, so you can use the tableview's section
as an index on the FRC's fetchedObjects
to identify the order for each section. The numberOrRowsInSection
can then be found by summing the count of products
and services
for the relevant Order
. The messy (and possibly slow) bit is mapping the table view's row to the correct element of either products
or services
.
import UIKit
import CoreData
class ExampleViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {
@IBOutlet weak var tableView: UITableView!
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
var orders = [Order]()
var startDate : NSDate = NSDate()
var endDate : NSDate = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultController.delegate = self
tableView.dataSource = self
tableView.delegate = self
fetchData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultController.fetchedObjects!.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let order = fetchedResultController.fetchedObjects![section] as! Order
return ((order.products?.count ?? 0) + (order.services?.count ?? 0))
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let textCellIdentifier = "ExampleTableViewCell"
let row = indexPath.row
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! ExampleTableViewCell
let order = fetchedResultController.fetchedObjects![indexPath.section] as! Order // Data fetched using NSFetchedResultsController
let products = (order.products?.allObjects ?? [Product]()) as! [Product] // Swift Array
let services = (order.services?.allObjects ?? [Service]()) as! [Service] // Swift Array
if (row < products.count) { // this is a Product row
cell.orderLabel.text = products[row].name!
} else { // this is a Service row
cell.orderLabel.text = services[row-products.count].name!
}
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let order = fetchedResultController.fetchedObjects![section] as! Order
return "\(order.date)"
}
func orderFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Order")
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
let predicate = NSPredicate(format: "date >= %@ AND date <= %@", startDate, endDate) // startDate and endData are defined elsewhere
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = predicate
return fetchRequest
}
func fetchData() {
let fetchRequest = orderFetchRequest()
fetchedResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath:nil, cacheName: nil)
do {
try fetchedResultController.performFetch()
}
catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
}
There are probably neater ways to code this; I'm not a Swift aficionado.
If you use the FRC delegate methods, you can at least watch for new/deleted Orders and add/delete sections to the TV as necessary, and you could use updates to reload the relevant section.
Separate array from core-data in tableView Sections
The problem is here
cell.textLabel?.text = players2[indexPath.row].names
You are only looking at the row number and are ignoring the section number. So with your example of 10 and 2 the row
will always be between 0 and 4.
So you need to do something like (not tested):
let rowsPerSection = players2.count / numberOfTeams
let rowInSection = indexPath.row + rowsPerSection * indexPath.section
cell.textLabel?.text = players2[rowInSection].names
Sectioning TableView and rows with Core Data Swift
Just a hint: If you're using CoreData and UiTableView use NSFetchedResultsController to make things much, much easier. If you're searching for a starting point & sample code - just create a new master-detail-application project in Xcode and turn on "Use Core Data" in the dialog.
Now, straight to your question: an example "implementation" of the NSFetchResultsController:
var fetchedResultsController: NSFetchedResultsController {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
let fetchRequest = NSFetchRequest()
// Edit the entity name as appropriate.
let entity = NSEntityDescription.entityForName("Event", inManagedObjectContext: self.managedObjectContext!)
fetchRequest.entity = entity
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sectionSortDescriptor = NSSortDescriptor(key: "startDate", ascending: true)
let secondSortDescriptor = NSSortDescriptor(key: "title", ascending: true)
let sortDescriptors = [sectionSortDescriptor, secondSortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: "startDate", cacheName: nil)
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
var error: NSError? = nil
if !_fetchedResultsController!.performFetch(&error) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//println("Unresolved error \(error), \(error.userInfo)")
abort()
}
return _fetchedResultsController!
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.fetchedResultsController.sections?.count ?? 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = self.fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
}
CoreData with tableView Sections
You need to base the frc on the Item
entity, and use the sectionNameKeyPath
to reference the Category
name:
var fetchResultsController: NSFetchedResultsController<Item>!
let request: NSFetchRequest<Item> = Item.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "list.name", ascending: true)]
fetchResultsController = NSFetchedResultsController<Item>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: “list.name”, cacheName: nil)
try? fetchResultsController?.performFetch()
fetchResultsController?.delegate = self
tableView.reloadData()
Populate Table View Sections with CoreData and Array
Here's a sample project that has your basic setup - https://github.com/nambatee/CombinedFolders1
The trick is to adjust the indexPath
. You're working with 2 sections but your NSFetchedResultsController
knows of only 1 section. So you need to be careful not to ask NSFetchedResultsController
for objects in section at index 1
.
Deleting a table view row with Swift 3 and CoreData
When you delete data in coreData it wont be saved by coreData unless you save the action. The delete action should be like this..
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
managedObjectContext.delete(sessions[indexPath.row])
do {
try managedObjectContext.save()
tableView.reloadData()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
How can I sort and show in correct section of a UITableview in swift using CoreData results
Ok I figured it out, phew was this confusing and took a lot of research.
Okay, so first thing you have to do is create a transient property on the data model. In my case I called it lettersection. To do this in the entity just create a new attribute and call it lettersection and in graph mode if you select it (double click it), you will see option in inspector for 'transient'. This means it won't be saved to the database and is used more for internal reasons.
You then need to manually set up the variable in the extension area of the model definition. Here is how it looks for me.
import Foundation
import CoreData
extension Inventory {
@NSManaged var addCount: NSNumber?
@NSManaged var barcode: String?
@NSManaged var currentCount: NSNumber?
@NSManaged var id: NSNumber?
@NSManaged var imageLargePath: String?
@NSManaged var imageSmallPath: String?
@NSManaged var name: String?
@NSManaged var negativeCount: NSNumber?
@NSManaged var newCount: NSNumber?
@NSManaged var store_id: NSNumber?
@NSManaged var store: Store?
var lettersection: String? {
let characters = name!.characters.map { String($0) }
return characters[0].uppercaseString
}
}
Once you do this, you simply call this new 'lettersection' with the fetchedResultsController like so...
let frc = NSFetchedResultsController(
fetchRequest: inventoryFetchRequest,
managedObjectContext: self.moc,
sectionNameKeyPath: "lettersection",
cacheName: nil)
and everything will work! It sorts by the name of my inventory items, but groups them by the first letters, for a nice A,B,C type list!
CoreData entities to UITableView with sections
I don't think this code is going to do what you want. Typically the NSFetchRequest
that you use to construct the NSFetchedResultsController
that populates a UITableView
or UICollectionView
must fetch the entity type you actually want to display (or things become complicated). Have you tried something like this?
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = appDel.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Word")
let letterSort =
NSSortDescriptor(key: "letter.letterName", ascending: true)
let wordSort = NSSortDescriptor(key: "word", ascending: true)
fetchRequest.sortDescriptors = [letterSort, wordSort]
fetchedResultsController =
NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: context,
sectionNameKeyPath: "letter.letterName",
cacheName: "dict")
fetchedResultsController.delegate = self
do {
try fetchedResultsController.performFetch()
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
}
Assuming that your word values and associated letters are correct, I think this should do what you want. It's also worth noting that the cacheName
must be unique in your application, so you might want something more complex than simply "dict"
.
Related Topics
My Uiviews Muck-Up When I Combine Uipangesturerecognizer and Autolayout
Today Extension with Uicollectionview Different Behaviour Compared to Single View Application
Geolocation by Iphone's Ip Address
What's Happening Behind the Scenes in Xctest's @Testable
How to Change the Nstimeinterval of an Nstimer After X Seconds
How to Use Po Command in Console (Debug Area)
iOS + Swift, How to Redirect to Itunes Purchase Page
Read Logs Using the New Swift Os_Log API
Avcapturesession and Avaudiosession Recording Video While Background Music Playing Only Works Once
In Collectionview How to Set Colors According to Selection
Fbsdkcorekit.Framework/Fbsdkcorekit: No Matching Architecture in Universal Wrapper
How to Make a Bullet List with Swift
Moya/Alamofire - Url Encoded Params with Same Keys
Circle Image in Cell Imageview and How to Resize It