In this Core Data Tutorial, we do very important and useful things: First we set NSFetchedResultsController, and do changes in the code, create displayOrder attribute.With LongPressGestureRecognizer we can reorder TableViewCells and update Core Data cells with displayOrder attribute, which saved immediately in Core Data.
iCloud Sync tutorials:
Why do you need to use FetchedResultsController, and not use just simple FetchRequest? Maybe after editing your attributes, your UITableViewController does not update right away. Maybe you have a very big database, and you would like to fetch just those, which show for the user on the screen, and when the user start to scroll you can fetch more data (setFetchBatchSize code). Or maybe you have other reason.
Please read the entire article, but, at least, this small part:
You use a fetched results controller to efficiently manage the results returned from a Core Data fetch request to provide data for a UITableView object.
While table views can be used in several ways, fetched results controllers are primarily intended to assist you with a master list view. UITableView expects its data source to provide cells as an array of sections made up of rows. You configure a fetch results controller using a fetch request that specifies the entity, an array containing at least one sort ordering, and optionally a filter predicate. The fetched results controller efficiently analyzes the result of the fetch request and computes all the information about sections in the result set. It also computes all the information for the index based on the result set.
In addition, fetched results controllers provide the following features:
A controller thus effectively has three modes of operation, determined by whether it has a delegate and whether the cache file name is set.
If you are planning to develop a larger app with more Entities and relationships and attributes, then you have to read all about NSFetchedResultsController, and must use the settings in the right way.
Now start the work!
The starting point is the 4. part of this Core Data tutorial.
Probably you will find these line there:
1.1. In MyTableViewcontroller.h file set NSFetchedResultsControllerDelegate method
Create NSFetchedResultsController property, and in .m file synthesize it:
1.2. Create the fetch request with NSFetchedResultsController.
You must use SortDescriptor when you use NSFetchedResultsCotnroller. For example, you can tell that you want to order your fetched data ascending by your “displayOrder” attribute.
You can use setFetchBatchSize after then create NSFetchedResultsController. At this point, we just put nil to key Path, because we use just single section in our UITableView. And I don’t want to use Cache, so I put nil to this part too.
If you are using a cache, you must call deleteCacheWithName: before changing any of the fetch request, its predicate, or its sort descriptors. You must not reuse the same fetched results controller for multiple queries unless you set the cacheName to nil.
1.3. Implementing Table View Data Source Method
Just put this code to your MyTableViewController, then when you insert or delete or change your TableView, the FetchedResultsController will do the updates. So you can use a fewer code in the future to do these things because the controller will do it for you.
But there will be a significant problem. We call sortDescriptor with “displayOrder” attribute, but in our model, we haven’t got displayOrder attribute yet. So we have to change our model:
1.4. Create displayOrder attribute for User Entity. Type: “Integer 32” Type, “displayOrder” name.
You can change model in earlier parts so that you can do it, just create the attribute, after then delete the User.m and .h file, and create them again (CreateManagedObjectSubclass). And of course, you can delete the app in the Simulator.
1.5. Replace the old code at the Table View settings for the new one to able to use the controller.
In viewDidLoad block instead this line, where you call appDelegate FetchRequest, what we did earlier:
self.myArray =[[appDelegate getAllUserRecords]mutableCopy];
We can use perform fetch, and nil the controller, and then set the myArray with the fetchedObjects of our controller:
Now you can test your app; it will work. But, you do not add displayOrder attribute to the user object. Therefore, your app can’t order them by “displayOrder” attribute. It’s logic. So we can add the number for every user when we create them.
1.6. Set displayOrder value for user:
Using this 2 line of code in your ViewController.h file in prepareForSegue block before NSError *error line:
So now, your ViewController.m file prepareForSegue code looks like this:
In MyTableViewController.m file, in tableView cellForRowAtIndexPath, change your cell.textLabel.text to show the displayOrder number before the user name. Change your line to this:
1.7. To clean your all old code, you need to change the UITableViewCellEditingStyleDelete method.
Because Controller will do the “deleteRowsAtIndexPaths” line, so you should delete here this line, and also you have to change the
self.myArray = [appDelegate getAllUserRecords] code to this:
self.myArray = [_fetchedResultsController.fetchedObjects mutableCopy];
1.8. Run your simulator, test your app, and you will see the ordered users fetched by NSFetchedResultsController, and you can delete them.
But you would like to reorder them.
Probably you will find these line there:
When you would like to reorder your TableViewCells without editing mode, you can use this perfect tutorial at raywenderlich.
As I know this code updated, because there were more bugs on IOS8, but I and some other developer try to find solutions, (you can see in comments), so finally, it works fine! (I didn’t check the updated code, but I use this, as I wrote in the comment so that you can copy this).
And please read the article to understand how this code works!
2.1. First, we create a Gesture, but you need delegate method too.
Put in your MyTableViewController.h file the UIGestureRecognizerDelegate to your interface, and this SnapshotView code to call:
- (UIView *)customSnapshotFromView:(UIView *)inputView;
2.2. In your viewDidLoad in MyTableViewcontroller.m file, set your TableViewEditing mode to No, Scroll enabled YES, and Create the UILongGestureRecognizer:
2.3. Put the moveRowAtIndexPath, canMoveRowAtIndexPath, editingStyleForRowAtIndexPath, and shouldIdentWhileEditinRowAtIndexPath codes:
2.4. Gesture Settings
Put the raywenderlich code and gesture settings, and Snapshot view helper to the bottom of your MyTableViewController.m file: (this is my final code, what I use, maybe not entire same which is on the raywenderlich website)
2.5. Test your App, Run, and try to drag and reorder your cells.
It woks fine! Great! But you can see, that your “displayOrder” number not change, because the new reorder state not saved into Core Data.
3.1. Use this short code in your handleLongPress: block in UIGestureRecognizerStateChanged: case before the “break” line.
should looks like this:
But it will be not perfect!
You need to use _fetchedresultcontroller.fetchedObjects everywhere in the TableView.
3.2. change self.myArray to _fetchedResultsController.fetchedObjects in your .m file.
These little things need to everything works together in a right way! If you didn’t do these, but use the method which will reorder your data and save into core data database, it would show that numbers change, but position not, or position change but numbers no, and other types of mistakes.
3.3. Create userchangeArray NSMutableArray:
In MyTableViewController.m after interface create the MutableArray, and set as _FetchedResultsController.fetchedObjects mutbalecopy top of your file:
3.4. Set the reorder method in handleLongPress: block case UIGestureRecognizerStateChanged:
Probably you will find these line there:
Now you can run your App in the simulator, and you can reorder your rows, and you will see, that your numbers change too as a new position of the cell/data.
If you use just commitEditingStyle UITableViewCellEditingStyleDelete - maybe now it not works, I suggest to use some of Swipeable Table View Cell to use this function, and create own gesture settings. (I will create a tutorial for this).
Download the Xcode template from Github.
The next part of the series: CoreData Tutorial Part 5/5 - Model Versioning, Lightweight Migration, Model Mapping
If you would like to be notified of my new solutions, please subscribe to my Newsletter or my youtube channel and/ or follow me on Facebook or Twitter! Check Footer section for these opportunities!