How to keep UITableView's datasource ordered in response to user moving rows around? - iphone

I have a UITableView and one of its sections is managed by a NSFetchedResultsController. It fetches core data objects and keep them sorted by the "order" attribute:
object with order 1
object with order 2
object with order 3
The requirement that I'm facing is that the user can move rows around. After move:
object with order 2
object with order 1
object with order 3
What do I need to do to ensure that the managed objects in core data reflect changes in order resulting from user moving table view rows around? When I'm working with GMGridView, there's a callback that exchanges two objects. In such case, changing their order works, but I do not see such function for a UITableView.
Would I need to manually change the order attribute for all objects that exist below the moved row?

You can use this:
- (NSIndexPath *) tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
Plus re-ordering your data-source, by exchanging the objects order.

You need to store an association between the fetched object and the 'row order'. You order the rows based on row order; the row order defaults to your 'order' attribute. When the user moves a row, you update the 'row order' as well.
You can maintain the association either in the CoreData object itself (add another attribute) or by mapping the fetched object to its row order (in NSUserDefaults or in just a NSDictionary).

Moving rows around does not just affect the order attribute of itself but all the rows behind it. A work around I have found is to copy the fetch request objects to an nsmutablearray then moving the object within this array. Then running a for loop and updating the order attribute in each object then saving the managed object context. Then reload the uitableview. This seems like a lot of work but currently moving objects in a fetch request is not automatic like insert and delete. I hope this helps!

Related

NSFetchedResultsController predicate to eliminate duplicates of several properties

I am using an NSFetchedResultsController in my UITableViewController.
Is it possible to specify a predicate that will not retrieve items which have duplicate fields in x number of fields that I specify.
For example, I want to search all results for items but if the itemName AND itemDescription AND itemQuantity are the same, I want only one of these items.
Option 1
When the page loads do a single run through the data and keep a list of objectID that are duplicate. For duplicate object set the row height of the cell to be 0. So they are technically still there, but you can't see it. This make dealing with the NSFetchedResultsControllerDelegate calls easy because no indexPaths have changed
Option 2
If the dataset is always selected in the same way and an object that is a duplicate is always a duplicate you can set an 'isDuplicate' in the object and filter it out in the predicate. Or you can not store at all in the first place. If objects are displayed in different sets and in different way and sometime should be displayed and sometime not be displayed this is not a good solution
Option 3
If you are sorting by the same criteria that make an object duplicate (that is duplicates always appear right next to a non-duplicate) and you are NOT using sections, then you can use sectionKeyPath. SectionKeyPath groups items together into sections. Group the duplicate and non duplicate together and then display every section as a single row (use the first item in each section). The indexPaths of the fetchedResultsController will not match the indexPaths of the tableview so you have to careful to convert them.
Option 4
Instead of accessing the objects from a fetchedResultsController do a fetch and and filter the array. Then use the array to display the objects. The downside is that you don't get updates on when objects change. This can be especially problematic is objects are deleted, as accessing a managedObject that's entity was delete can lead to a crash.
I recommend option 1

Mapping a dataset to textfield inside UItableView

In my app, I am using some .net asmx services (as backend) to get some data and populating it on my views. In one of the modules, i need to edit and save the data which am getting from the services.In that am getting several rowkeyvalues and accordingly am creating those many row cells in my tableview, which consists two UItextfields as well, which displays some unique code and comments.
Now if I have to edit and save some fields, I need to map each one of those rowkeys to each row cell and after that am creating object which is basically the wsdl proxy class which I have generated using Sudzc and pass each dataset and serialize it to XML and POST it through SOAP.
The real problem here, am not getting how to map each unique rowkeys to each row cell and create unique dataset(which mainly contains other fields as well including rowkey) for each row and pass it to proxy object (WSDL stubs).
Not sure I understand your problem, but there are 2 ways I can think of to map a row cell to something.
1. Each UITableViewCell is a subclass of UIView, and so it has a "tag" attribute, which is an int.
You can set this and check it's value.
2. When a user taps a row, the tableView:didSelectRowAtIndexPath: is called. IndexPath.row is an int that gives the absolute row postiion within it's section (and if only one section, then in the whole table).
Usually, in cellForRowAtIndexPath: you fetch your backing data corresponding to the IndexPath.row and populate the cell. You could also set the cell's tag at that point.
This ties together the row, the cell and the data.
Hope that helps.
-Mike

Dynamic Sections UITableView with Unknown cells

Hey,
I'm basically trying to retrieve data from SQlite db and populate a tableView from it.
The sql-data-retrieval method creates two arrays. "dataArray" and "SectionArray".
DataArray is filled with data NSObjects.
Uptil this point, i can create the appropriate Section headers.
Here is the problem,
-1 What do i do to make sure that the right objects get into their appropriate sections and not under any other sections (which they seem to be doing). Also the Count(number of rows) in each section differs.
What should the code be in "NumberOfRowsAtIndexPath" and cellForRowAtIndexPath methods
-2 What kind of datasource objects are more suited for this type. I'm simply filling up two NSMutableArrays - dataArray(rows) and SectionArray(Section headers).
I think you should make many NSArray one for each table header you have created. In NumberOfRowsAtIndexPath you will return the count of the array for the requested section, and in cellForRowAtIndexPath you will choose your array using the section index (as before) and with the row index you will select the row of that array.

How can I return the count of objects for an FRC fetch?

I am trying to use the count of objects from my FRC fetch so that I can create an "Add" cell after all of my fetched objects have been listed in a UITableView. Is there a method for returning the number of objects fetched? I can only find a method that returns the count of sections for a given FRC.
Simplistically, you You want a count of fetchedObjects. So:
[[myFRC fetchedObjects] count];
The problem that you're going to have with adding an additional cell, is that every time the table ask for the count of sections and rows, you're going to have add 1 to the count so the table knows to add the extra row.
Bjarne Mogstad is correct. It's quicker and cleaner to put the add element in a header or footer for the table itself. That way, the table directly and cleanly represents the data structure without having to constantly adjust for the phantom row.
The easiest way to do this is by setting the tableFooterView property of your table view. The footer view will be displayed below the last table view cell.

Moving UITableView cells and maintaining consistent data

I've enabled editing mode and moving cells around to allow users to position table view content in the order they please. I'm using Core Data as the data source, which sorts the content by the attribute "userOrder". When content is first inserted, userOrder is set to a random value. The idea is that when the user moves a cell around, the userOrder of that cell changes to accomodate its new position. The following are problems I am running into while trying to accomplish this:
Successfully saving the the new location of the cell and adjusting all changed locations of influenced cells.
Getting the data to be consistent. For example, the TableView handles the movement fine, but when i click on the new location of the cell, it displays data for the old cell that used to be that location. Data of all influenced cells gets messed up as well.
I know I have to implement this in:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {}
I just don't know how. The apple docs are not particularly helpful if you are using Core Data, as in my situation.
Any guidance greatly appreciated!
Problem 1 is pretty much independent of using CoreData, just think of a simple array:
{0 1 2 3 4 A}.
Now the user moves some freshly appended element A within the Array:
{0 1 A 2 3 4}
So starting with the inserted element A, which receives the index 2, all elements need to have their index (which is userOrder in your case) incremented by one.
So you map 0->0, 1->1, A->2, 2->3, 3->4 and so on.
Problem 2 may have two or three sources:
Either your CoreData values are not synced so the database is not in sync with what you see.
[table reloadData] was not called
Your move-Algorithm is wrong
So perhaps you can check the thee points above and if none applies you could consider posting your move-algorithm for closer examination.