I'm using Core Data and KVO to look for changes in values to trigger saves to the data store. I have a table view with search hooked up to NSFetchedResultsController. When the search changes, a new results controller is made on pressing the Search button. When the user selects an item in the results table view, then the user enters a detail view and can make edits.
This is where I encounter the problems. When the user makes a change in a separate UIControl that I made, the detail view is notified and can use the NSFetchedResultsController it remembers from when the table view pushed me onto the view stack to get the NSManagedObjectContext and do a save. When I do so, I sometimes get the following error:
Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. no object at index 89 in section at index 0 with userInfo (null)
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 89 in section at index 0'
I found that this tends to happen when I do a search and an object that isn't on the top of the table is moved up to the top. I vaguely know what might be wrong in the back of my head, but would appreciate any pointers as to how to fix this.
I figured out what was wrong. I forgot to unset the old NSFetchedResultsController's delegate, and also forgot to release said NSFetchedResultsController. My UITableView subclass also responded to updates to the NSFetchedResultsController through delegates, and caused weird calls to be made.
Related
I am new to ios development and I am trying to create a simple test app that allows users to record and edit their pills in their medicine cabinet.
I am using ios 6.1, arc and segues.
Background to the error:
So the user has a list of pills in their medicine cabinet, he picks one and a segue brings him to a view controller that gives him information about that pill. He then has the option to edit the info which segues him to another view controller that shows all the current info in textfields which he can edit and then click a save button which initiates an unwind segue to the original medicine cabinet.
The error I am getting is this. The user can edit the info and save it successfully and pop back to the cabinet. But then when he goes to edit the pill again, I get the error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString appendString:]: nil argument'
I did some digging and I found out what is happening. In the unwind segue method,I am successfully setting the properties of the pill to match the text in the textfield of the editPillView controller. For example, I have a pill and it belongs to Jay. But then I edit it and say it belongs to Raf. Using breakpoints, I can see the string change from Jay to Raf in the unwind segue method of the MedicineCabinetViewController. But once the unwind segue is complete, I see that at some point, the string gets set to nil in apple's code (probably because arc is deallocing memory because the EditPillViewController is no longer needed and the pill's owner property then becomes a null pointer). Then when the user clicks the pill again, the pillInfoViewController is trying to use the null pointer and BOOM.
I've tried so many solutions to try to keep the string to stay raf such as using the NSString copy method. Any ideas?
When you do an unwind segue, any controllers from the one you're unwinding from, back to but not including the one you're unwinding to, will be deallocated unless you have a strong reference to them. So, the pill's owner property, if it's in MedicineCabinetViewController, will go away when the controller is deallocated.
There are several ways you can fix this problem. One way, would be to navigate in your app using code rather than using segues, so you can keep references to the controllers you create, and only allocate one if it doesn't exist yet.
Another way would be to have a model class that's a singleton, which would live for the life of the app. That way all the data concerning the medicines would be properties of some object (or objects) in this singleton class.
I have created a window based application with the following
a TableViewController (Without a XIB file)
a ViewController (With a XIB file) <-- to be used as modal view
a CoreData model to store some data
I managed to load the application and populate the TableView with the data from the Entity, and I was able to scroll through all of the cells of the TableView, without any issues.
I added a UIBarButton item (rightBarButton) that causes a Modal View to appear for the user to input some data. The model view has a SAVE and CANCEL buttons.
The problem is once I press the Cancel Button, I go back to the TableView but if I try to scroll throgh the items in the tableview, the app crashes.
After 4 hours of searching Google and StackOverflow, I was not able to see why my app crash. I did however notice by the debugger that the ManagedObjectContext is set to NIL the second time I scroll the tableview (after the modalview is dismissed), although no data is changed and no insertion/deletion occured.
I tried using a timer to call reloadData as I found some answers on StackOverflow, but that did not work. I tried setting the ManagedObjectContext as a property with retain and removed all occurences of [myManagedObjectContext release] to avoid releasing it earlier than needed, but that did not help.
It seems that I am doing an obvious mistake, but I am not sure where.
Please help.
ivars do not become nil just because they're released somewhere else (at least not in iOS 4.3). So an over-release is not the specific cause of myManagedObjectContext becoming nil. Assuming you're using accessors to reference your ivars (and you should be), hand-implement setManagedObjectContext: and put a breakpoint in there to see who's calling it. Alternately, you can add a gdb watchpoint to myManagedObjectContext to see when the memory is changed.
You haven't indicated what the crash stack is when you crash. You should be focused on what memory you're accessing at the point of the crash, and ensuring that the crash is due to a memory violation rather than an exception. Check your debugger output. Often it will tell you what's happening.
In my UIView I've got a UITableView (UITV) which is controlled by an NSFetchedResultsController (NSFRC). The UIView is inside a UINavigationController.
When the view is about to be loaded/displayed I start some background activities which fetch data from a remote server (JSON) and parse into Core Data.
The NSFRC is being called when the parsing is done and the threaded NSManagedObjectContext have been merged into the main context.
The problem is that sometimes many rows are being inserted to Core Data at once, a lot of table cells are being added and there is quite a delay from that the actual fetching and parsing is done, until the rows are being displayed.
Now I wonder if anyone knows of any solution to, for example:
hook up a spinner to some "fetched results controller inserted all its rows for this time" (or something) notification/delegate call to at least tell the user that "something is going to show up soon"?
Or might the best solution simply be to not initialize the NSFRC until the background fetching and processing is completed?
Thanks!
If I understand your question correctly, you may want to look into the NSFetchedResultsControllerDelegate methods, with documentation available here: http://developer.apple.com/library/ios/#documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html
There are delegate methods available for pre changes with controllerWillChangeContent:, post changes with controllerDidChangeContent and during changes with didChangeSection: and didChangeObject.
I hope it helps!
Rog
I have a UITableViewController backed by a NSFetchedResultsController.
I'm currently experiencing a SIGABRT when deleting a row, after I save the managedObjectContext in commitEditingStyle.
The crash then happens in drawRect: in my UITableViewCell where it tries to access the core-data object for this row:
[self.document.name drawAtPoint:...]
The SIGABRT exception is:
<0x7f883f0 DocumentListControllerCell.m:(108)> CoreData could not fulfill a fault
for '0x7f2a600 <x-coredata://A71C21B4-FE2A-4D1B-A76F-A2AB80E4814C/Document/p16>'
Of course the issue is that the CoreData object has been deleted and cannot be accessed anymore. I wonder why drawRect is still called for this cell.
Any help would be appreciated!
when deleting a row also at that same time delete it from core data so that there is no redundant data that is being drawn.
Happened many times to me where i delete something from the table but not from where i was fetching the data and this would crash my app as it would draw the table properly when endcommit style was called.
So just make those changes and everything should be fine
PK
I see one solution but I would like to know if it's the correct way to solve this problem.
The issue currently is that drawRect in the cell access the CoreData "document" which was deleted, to get the document name and draw it. Instead of doing that, I could cache the document name in a string in setDocument and directly access this string.
It seems like it would be the right way to do that. Could someone confirm that I should not access the Core Data object in drawRect ?
Following steps result in a crash in NSFetchedResultsController.
I try to add the first element to a NSFetchedResultsController backed TableView.
I create a temporary MO object and display a Modal View pane to add new object.
On the Add Sheet (a Modal View Controller), I press Cancel Button to discard the new element.
In the CancelAction callback for Cancel button, I delete the new temporary object I created.
The code till here is exactly similar to Apple sample code for Core Data. The only extra code I have is a call to [tableView reloadData] after the Add sheet is dismissed.
The crash results only if I try to add the first element, since it is related to wrong section count in NSFetchedResultsController.
This results in a crash given below. If I remove redundant call to reloadData, the crash is not visible. If I add a reloadData call to Recipe sample code data, the crash happens there as well.
Is it a known problem with NSFetchedResultsController?
2009-09-13 18:22:45.600 Recipes[14926:20b] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'
As you discovered by yourself, you should NOT use [tableView reloadData], because you are probably using the NSFetchedResultsController delegate methods
– controllerWillChangeContent:
– controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:
– controller:didChangeSection:atIndex:forChangeType:
– controllerDidChangeContent:
These methods are actually in charge of updating your table view when you add, delete or modify objects. Therefore, when you add the call to [tableView reloadData] what happens is that two different threads are both accessing/modifying your table view. This causes the crash you are experiencing.
If you are not using the delegate methods, then the crash is due to something else in your code.