Reputation: 1712
Any ideas on the following? Help greatly appreciated:
I have setup an NSFetchedResultsController
as follows:
var _fetchedResultsController: NSFetchedResultsController?
var fetchedResultsController: NSFetchedResultsController {
if self._fetchedResultsController != nil {
return self._fetchedResultsController!
}
let entity = NSEntityDescription.entityForName("Messages", inManagedObjectContext: self.mOC)
let messageRequest = NSFetchRequest()
messageRequest.entity = entity
let messagePredicate = NSPredicate(format: "messageFrom = %@ OR messageTo = %@", profileID, profileID)
messageRequest.predicate = messagePredicate
messageRequest.fetchBatchSize = 20
let sectionSortDescriptor = NSSortDescriptor(key: "messageDate", ascending: true)
let sortDescriptors = [sectionSortDescriptor]
messageRequest.sortDescriptors = sortDescriptors
let frc = NSFetchedResultsController(fetchRequest: messageRequest, managedObjectContext: self.mOC, sectionNameKeyPath: "sectionTitle", cacheName: nil)
frc.delegate = self
self._fetchedResultsController = frc
return self._fetchedResultsController!
}
It's linked by a to-many relationship with a Chats Entity. Chats >> Messages. One chatter (defined by CurrentChatter) has many messages.
When I load the tableview ... the messages show perfectly using the following in my ViewDidLoad()
:
do {
try fetchedResultsController.performFetch()
} catch let fetchError as NSError {
print("I have been unable to fetch things .. : \(fetchError)")
}
When I save a message using the following boilerplate code, nothing seems to be happening with the NSFetchedResultsController
. The tableView isn't updating for some reason and I can't seem to work out why. I have the NSFetchedResultsControllerDelegate
in place and defined.
if let newMessage = NSEntityDescription.insertNewObjectForEntityForName("Messages", inManagedObjectContext: mOC) as? Messages {
newMessage.messageDate = NSDate()
newMessage.messageFrom = myMainUser.mainUserIDfromServer
newMessage.messageMustBeSent = false
newMessage.messageReceivedAtServer = true
newMessage.messageCode = 0
newMessage.messageType = 100
newMessage.messageText = "Here is a message I am sending to you!"
newMessage.messageTo = Int(profileID)!
newMessage.messageNewMessage = false
currentChatter.mutableSetValueForKey("messages").addObject(newMessage)
do {
try mOC.save()
} catch let saveError as NSError {
print("I have not been able to save the message ...: \(saveError)")
}
}
I'm calling mOC.save. I've checked that it's saved and that it's saving to the same ManagedObjectContext
. When I manually refresh the tableview, the new message shows.
To test this is working I have a simple print statement as follows:
func controllerWillChangeContent(controller: NSFetchedResultsController) {
print("I will make changes?")
}
Needless to say, this isn't getting called.
Is this because the new message is being added as part of my CurrentChatter. Or should it update each time there is a change to the Messages Entity? Or have I missed something entirely? 3 hours on this and I'm no closer to understanding why it's not working.
Thanks in advance.
UPDATE:
I've added code to sort the table by Date (added for reference):
import Foundation
import CoreData
class Messages: NSManagedObject {
func sectionTitle() -> String {
let myDate = NSDateFormatter()
myDate.dateFormat = "d MMM YYYY"
return myDate.stringFromDate(self.messageDate)
}
}
Upvotes: 1
Views: 2913
Reputation: 5400
I had a similar issue. In my case, the problem was that I had set the NSFRC delegate on the type variable before instantiating it with a result from NSFetchedResultsController()
call. So the delegate was not being set and none of the delegate methods would work.
Silly mistake, I know, but took me a while to find it.
In your case, if you are getting back something for type
in didChangeObject
then your delegate is working fine.
You said you were getting the wrong values for type
. Print the raw value of the type
enum to see what they are. Here is a link to Apple's doc on them:
Their order in the switch
statement shouldn't matter as long as it is extensive (include them all).
Also, make sure that you are not expecting one type and receiving another. For example:
If adding a new entry, you would expect a .Insert
correct? But if you are sorting by name
in the NSFRC descriptor, you will receive a .Move
instead because the new addition could cause a rearrangement of rows.
This also happened to me and took me a while to find.
Hope this helps a bit.
Upvotes: 2
Reputation: 1578
If you place the update statement BEFORE the .Insert in the didChangeObject (so put it on the first place), does that help? I had the same behavior and this fixed it for me.. At least, on my device. I now hear beta testers experiencing the same issue.. :(
Upvotes: 0
Reputation: 11555
You set the delegate, but did you implement controller didChangeObject
etc.? You need something like this:
func controllerWillChangeContent(controller: NSFetchedResultsController) {
tableView.beginUpdates()
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Insert:
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
case .Delete:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
case .Update
// update cell at indexPath
case .Move:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.endUpdates()
}
Upvotes: 2