sectionNameKeyPath NSFetchedResultsController gets ignored - Swift - ios

I followed this suggestion:
Format sectionNameKeyPath NSFetchedResultsController - Swift
I'm having a bit of a problem with this implementation.
Using Xcode 8 and iOS 10.
I set Codegen to Manual/None and added my NSManagedObject Subclasses.
Then I added as you suggested:
var sectionIdentifier: String
{
get
{
let dateFormatter = DateFormatter()
// dateFormatter.dateStyle = .short
// dateFormatter.timeStyle = .none
// ..or to stick to your original question:
dateFormatter.dateFormat = "yyyy-MMM-dd"
return dateFormatter.string(from: date! as Date)
}
}
But for whatever reason it gets ignored by sectionNameKeyPath. When I enter "date" in sectionNameKeyPath I get the same result as AllReadyHome mentioned above.
I even tried:
return (date?.description)!
It didn't yield any results.
Maybe someone can point me in the right direction...
Update 1:
That's what my fetchedResultsController look like:
let fetchRequest: NSFetchRequest<Time> = Time.fetchRequest()
fetchRequest.fetchBatchSize = 20
let sortDescriptor = NSSortDescriptor(key: "date", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: "sectionIdentifier", cacheName: "Time")
Result: No sections
When using date, which is an attribute of my entity:
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: "date", cacheName: "Time")
It looks like this:
Update 2:
When using the sortDescriptor as suggested, I get a crash ("sectionIdentifier not in entity):
let fetchRequest: NSFetchRequest<Time> = Time.fetchRequest()
fetchRequest.fetchBatchSize = 20
let sortDescriptor1 = NSSortDescriptor(key: "sectionIdentifier", ascending: false)
let sortDescriptor2 = NSSortDescriptor(key: "date", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2]
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: "sectionIdentifier", cacheName: "Time")
Update 3:
I get the following warning when getting to the screen:
A section returned nil value for section name key path 'sectionIdentifier'. Objects will be placed in unnamed section
CoreData: error: (NSFetchedResultsController). A section returned nil value for section name key path 'sectionIdentifier'. Objects will be placed in unnamed section

use #objc for your sectionIdentifier
Sample:
#objc var sectionIdentifier: String {
get {
return ""
}
}

Related

How to update view after clearCoreDataStore()?

I have a button that calls clearCoreDataStore(). However, after it gets executed the view does not update, it still shows content. How can I update that?
On a related note, how can I update the view after I got data inserted to the app's Core Data stack?
I have the following 'fetching' code outside the class declaration:
fileprivate var fetchedResultsControllerForMapEntity:
NSFetchedResultsController<Map> = {
// Create Fetch Request
let fetchRequest: NSFetchRequest<Map> = Map.fetchRequest()
// Configure Fetch Request
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
// Create Fetched Results Controller
let fetchedResultsControllerForMapEntity =
NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultsControllerForMapEntity
}()
fileprivate var fetchedResultsControllerForCoordinateEntity: NSFetchedResultsController<Coordinate> = {
// Create Fetch Request
let fetchRequest: NSFetchRequest<Coordinate> = Coordinate.fetchRequest()
// Configure Fetch Request
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "latitude", ascending: true)]
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "longitude", ascending: true)]
// Create Fetched Results Controller
let fetchedResultsControllerForCoordinateEntity = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultsControllerForCoordinateEntity
}()
and on viewDidLoad, I do:
do {
try fetchedResultsControllerForMapEntity.performFetch()
try fetchedResultsControllerForCoordinateEntity.performFetch()
} catch

Ios Swift3 : lazy var fetchrequestcontroller showing an error

I was using a lazy var in table view controller to get the data from CoreData. It was working good in swift2. But When I upgraded to Swift3, Its showing an error as below. Kindly help me to change for Swift3
Error : Cannot convert value of type 'Error' to specified type 'NSFetchedResultsController'
lazy var fetchedResultsController: NSfetchedResultsController =
{
let fetchRequest = NSFetchRequest(entityName: "EvtIvtTbl")
let sortDescriptor = NSSortDescriptor(key: "bym_kol", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
let fetchedResultsController = NSfetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: self.managedObjectContext,
sectionNameKeyPath: nil,
cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}()
In Swift 3.0, NSFetchedResultsController and NSFetchRequest want type parameters. Assuming that EvtIvtTbl is your NSManagedObject subclass, your code should look like this:
lazy var fetchedResultsController: NSFetchedResultsController<EvtIvtTbl> = {
let fetchRequest = NSFetchRequest<EvtIvtTbl>(entityName: "EvtIvtTbl")
let sortDescriptor = NSSortDescriptor(key: "bym_kol", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
let fetchedResultsController = NSFetchedResultsController<EvtIvtTbl>(fetchRequest: fetchRequest,
managedObjectContext: self.managedObjectContext,
sectionNameKeyPath: nil,
cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}()

convert syntax to swift 3.0 NSFetchedResultsController

how can I convert my NSFetchedResultsController to swift 3.0, i can't get it to work.... I tried apple's auto conversion but it's not working??
I had this:
lazy var fetchedResultsControler: NSFetchedResultsController = {
let fetchRequest = NSFetchRequest(entityName: "Mesages")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: true)]
fetchRequest.predicate = NSPredicate(format: "user.id = %#", self.friend!.id!)
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = self
return frc
}()
automatically converted to this:
lazy var fetchedResultsControler: NSFetchedResultsController = { () -> <<error type>> in
let fetchRequest = NSFetchRequest(entityName: "Mesages")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: true)]
fetchRequest.predicate = NSPredicate(format: "user.id = %#", self.friend!.id!)
let moc = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = self
return frc
}()
but It's not working, it's asking me to put semi colons in random places
It is needed to set up NSFetchRequestResult inside brackets <>.
For swift 3.0:
lazy var fetchedResultsControler: NSFetchedResultsController<NSFetchRequestResult> = {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Mesages")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: true)]
fetchRequest.predicate = NSPredicate(format: "user.id = %#", self.friend!.id!)
let moc = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = self
return frc
}()

Load more in bottom UITableView using NSFetchedResultsController

I want to load more cells when user in the last cell. I use CoreData and I get data from it. I use this answer to do what I want, but it didn't work. What problem can be there? Also I have one more question. I don't know why working only first implementation.
First implementation
var fetchedResultsController: NSFetchedResultsController {
let moc = DatabaseController.sharedInstance.managedObjectContext
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Coctail", inManagedObjectContext: moc)
fetchRequest.entity = entity
fetchRequest.fetchLimit = 10
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: moc,
sectionNameKeyPath: nil,
cacheName: nil)
aFetchedResultsController.delegate = self
do {
try aFetchedResultsController.performFetch()
} catch {
fatalError("\(error)")
}
return aFetchedResultsController
}
Second Implementation
func initilizeFetchedResultsController() {
let moc = DatabaseController.sharedInstance.managedObjectContext
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Coctail", inManagedObjectContext: moc)
fetchRequest.entity = entity
fetchRequest.fetchLimit = 10
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: moc,
sectionNameKeyPath: nil,
cacheName: nil)
aFetchedResultsController.delegate = self
do {
try aFetchedResultsController.performFetch()
} catch {
fatalError("\(error)")
}
fetchedResultsController = aFetchedResultsController
}
Hard to tell why the first solution but the second doesn't without seeing the other code that would have used the fetchedResultsController or called initilizeFetchedResultsController().
The reason you're not getting more data is that you've hardcoded your fetchLimit to 10. No matter what you do, you'll only ever get 10 results.
You'll need to change the fetchLimit to get more data. Check out this answer -- it is similar to what you'll need to do: https://stackoverflow.com/a/6786931/5605379

filter NSFetchedResultsController result swift 2

I want automatic updates on tableview..For that i have used NSFetchedResultsControlleras
lazy var fetchedResultsController: NSFetchedResultsController = {
// Initialize Fetch Request
let fetchRequest = NSFetchRequest(entityName: "Student")
// Add Sort Descriptors
let sortDescriptor = NSSortDescriptor(key: "grade", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
// Initialize Fetched Results Controller
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
// Configure Fetched Results Controller
fetchedResultsController.delegate = self
return fetchedResultsController
}()
But i have to filter the results after loading as of user selection as..
#IBAction func onSegmentValueChanged(sender: UISegmentedControl)
{
if sender.selectedSegmentIndex == 0{
//filter by grade
let fetchRequest = NSFetchRequest(entityName: "Student")
let sortDescriptor = NSSortDescriptor(key: "grade", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
let filterfetchResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
let predicate = NSPredicate(format: "address = %#","Russia")
filterfetchResultsController.fetchRequest.predicate = predicate
self.tableView.reloadData()
}else{
let fetchRequest = NSFetchRequest(entityName: "Student")
let sortDescriptor = NSSortDescriptor(key: "grade", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
let filterfetchResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
let predicate = NSPredicate(format: "grade = %d",10)
filterfetchResultsController.fetchRequest.predicate = predicate
self.tableView.reloadData()
}
}
This however reload the tableView but data is not filtered.how do i solve this problem?This is the demo project i am working on.Or should i use the normal way passing the results and reloading tableView as of normal way to solve this problem?
You must use self.fetchedResultsController, this is your datasource, not filterfetchResultsController: thereĀ“s no connection.
You must do a performFetch() to execute the changed predicates
This works for me:
#IBAction func onSegmentValueChanged(sender: UISegmentedControl)
{
if sender.selectedSegmentIndex == 1{
//filter by address
let predicate = NSPredicate(format: "address == %#","Russia")
self.fetchedResultsController.fetchRequest.predicate = predicate
}else{
let predicate = NSPredicate(format: "grade = %d",10)
self.fetchedResultsController.fetchRequest.predicate = predicate
}
do {
try self.fetchedResultsController.performFetch()
} catch {
let fetchError = error as NSError
print("\(fetchError), \(fetchError.userInfo)")
}
self.tableView.reloadData()
}

Resources