How to use UITableView when total number of sections and rows are unknown (and potentially large) - iphone

Normally to use UITableView, the number of sections and rows per section are known. But what if they aren't? I want to implement a lazy search, so that I actually search for the next match when new data needs to be displayed. Something on the lines of: db.prepareSearch(query) and then call something like db.nextSearchResult() when it is time to display a new cell. The search result determines if a new section is required or not (search results are inherently sorted).
Not sure why it wasn't done this way to begin with, so that it asks for a section until no more are available or needed, and for cells in the section until no more are available or needed, instead of having to specify the totals, which implies having to finish the whole search before starting to display the first few results.

To get the number of sections and rows, it's easy -- ask your data source. If your data source has no way of telling you this, make a way.
For instance, if you have to query a table and ask how many rows there are for your sections, do that. Then, for each section, ask how many rows there are which match that section.
What it also sounds like is you want to paginate your data. Meaning when you get to a certain point, have a "load more data" cell or some-such. This is fine too, just add a sentinel node to your data source, and whenever that particular item comes up, display your alternate cell while you load your data, then remove it after your next data is fetched. I do this in a few of my apps.

If I'm understanding this correctly, at the point of drawing/populating, you will know how many rows/sections you have.
If your changing the underlying data using db.nextSearchResult() then you must be calling [tableView reloadData] to trigger a UI update, at this point you should know how many sections and rows you have.
I have to admit I'm a little confused to the exact issue here.

Related

Restricting access to some columns in a table, based on another column in the same row

This feels like it should be a common requirement, but I'm not sure how best to implement the requirement.
I'm going to make up a really simple example. It's similar enough to what I actually need, without getting over-complicated.
Imagine we have a table called transport and it has the following columns:
type
model_name
size
number_of_wheels
fuel
maximum_passenger_count
We want to store all sorts of different types of transportation in this table, but not every type will have values in every column. Imagine the commonality is a lot higher, as this is a bit of fake example.
Here's a few examples of how this might work in practice:
type = cycle, we ban fuel, as it's not relevant for a cycle
type = bus, all columns are valid
type = sledge, we ban number_of_wheels, as sledges don't have wheels, we also ban fuel
type = car, all columns are valid
I want my UI to show a grid with a list of all the rows in the transport table. Users can edit the data directly in the grid and add new rows. When they add a new row, they're forced to pick the transport type in a dropdown before it appears in the grid. They then complete the details. All the values are optional, apart from the ones we explicitly don't want to record a value for, where we expect to not see anything at all.
I can see a number of ways to implement this, but none of them seems like a complete solution:
I could put this logic into the UI, enabling/ disabling grid cells based on type. But there's nothing to stop someone directly inserting data into the "wrong" columns in the backend of the database or via the API, which would then come through into the UI unless I added a rule to also mask out values in disabled cells. Making changes to which columns are restricted per transport type would be very difficult
I could put this logic into the API, raising an error if someone enters data into a cell that should be disallowed. This closes one gap for insertion to the database via the API, but SQL scripts would still allow entry into the "wrong" column. Also, the user experience would suck, as users would have to guess which columns to complete and which to leave blank. It would still be difficult to make changes to which columns are allowed/ restricted
I could add a trigger to the database, maybe to set the values to NULL if they shouldn't be allowed, but this seems clunky and users would not understand what was happening
I could add a generated column, but this doesn't help if I sometimes need to set a value and sometimes don't
I could just allow the unnecessary data to be stored in the database, then hide it by using a view to report it back. It doesn't seem great, as users would still see data disappearing from the UI with no explanation
I could add a second table, storing a matrix of which values are allowed and which are restricted by type. The API, UI and database could all implement this list using different mechanisms - this comes with the advantage of having a single place to make changes that will immediately be reflected across the entire system, but it's a lot of work and I have lots of these tables that work the same way

Database and item orders (general)

I'm right now experimenting with a nodejs based experimental app, where I will be putting in a list of books and it will be posted on a forum automatically every x minutes.
Now my question is about order of these things posted.
I use mongodb (not sure if this changes the question or not) and I just add a new entry for every item to be posted. Normally, things are posted in the exact order I add them.
However, for the web interface of this experimental thing, I made a re-ordering interaction where I can simply drag and drop elements to reorder them.
My question is: how can I reflect this change to the database?
Or more in general terms, how can I order stuff in general, in databases?
For instance if I drag the 1000th item to 1st order, everything below needs to be edited (in db) between 1 and 1000 the entries. This does not seem like a valid and proper solution to me.
Any enlightenment is appreciated.
An elegant way might be lexicographic sorting. Introduce a String attribute for each item. Make the initial length of the values large enough to accomodate the estimated number of items. E.g., if you expect 1000 items, let the keys be baa, bab, bac, ... bba, bbb, bbc, ...
Then, when an item is moved from where it is to another place between two items, assign a value to the sorting attribute of the moved item that is somewhere equidistant (lexicographically) to those items. So to move an item between dei and dej, give it the value deim. To move an item between fadd and fado, give it the value fadi.
Keys starting with a were initially not used to leave space for elements that get dragged before the first one. Never use the key a, as it will be impossible to move an element before this one.
Of course, the characters used may vary according to the sort order provided by the database.
This solution should work fine as long as elements are not reordered extremely frequently. In a worst case scenario, this may lead to longer and longer attribute values. But if the movements are somewhat equally distributed, the length of values should stay reasonable.

Sorting cells in UITableView into sections, after TableView has been loaded

Right, so my UITableView loads and puts all the cells in Alphabetical order. Information is then downloaded from a server and calculations are done, with the TableView being reloaded once everything is complete. Currently this is quite a simple procedure as once the information is downloaded from the server, the cells don't even move, they are left in their alphabetical order. Nothing really happens other than half of the information is filled in and small changes are made depending on the calculations. I was wondering if there was an easy way of putting the cells into sections depending on the calculations done after the download is complete? I did have an idea of creating 4 arrays (there will only be 4 sections ever) and once isLoading is set to no, changing the data source of the TableView to have sections, however, that sounds a bit... iffy. I know this is a theoretical question as opposed to a coding problem, but before I go and mess up my code, in what is sure to be a stupidly inefficient way of doing things, is there an easy way of "assigning" UITableViewCells to sections?
My main issue with my way of doing it is that should the user delete a cell, deleting the appropriate entry in Core Data will be a little tricky and prone to errors. This lead me on to another idea. What if I added an extra attribute to my Core Data entity. That attribute would be assigned and then saved once the calculations were done. The problem with this is that no existing databases would work. There has to be a neat way of achieving this.
Thanks for the help. If you need me to post any code just say so and I will.
You should be fine if you implement the data source methods related to sections.
For example:
numberOfSectionsInTableView
sectionIndexTitlesForTableView.
Any time the table data is reloaded (e.g., [self.tableView reloadData]), these methods will be called and the data will be placed into their sections.
Keep in mind that the cells are just the visual representation of your model, which in this case is your fetched data. The cells are not assigned to sections; they are simply created however you specify for your model (via the table view data source and delegate methods).
Regarding deletion of entries while using Core Data, I suggest taking a look at NSFetchedResultsController. The latter will monitor any changes to your table's data and message its delegate, your table view controller, when updates are made.
For example, a deletion would start with a call to the table view delegate like normal (i.e., via tableView:didEndEditingRowAtIndexPath). Within the latter, you would then delete the entry from core data (e.g., [self.myDatabase.managedObjectContext deleteObject:entity]). Assuming you initiated the NSFetchedResultsController w/ the same managed object context, the deletion would be automatically reflected back to your user.
If you're using a remote DB, however, you'll also have to perform a save (however you've implemented that) to ensure the DB is updated too.
Note also that if you use an NSFetchedResultsController, you don't need to implement the section data source methods since NSFetchedResultsController can handle that for you. Just define the key-path in your data model that will return the section name when initializing the NSFetchedResultsController.

how to combine two UITableview in single UITableview's section?

I want to set two different UITableview in single UITableview's particular section. Is it possible??
To do exactly what you are asking is not possible. but I think that you did not phrase what you want correctly.
You probably want to show data from 2 different table views in one section. As you probably know each tableView has a Data Source. All you got to do in order to show data from the 2 tables is to manipulate the Data Source to return exactly the data you are expecting, i.e. joining the 2 data source content for this section together.

how to implement picker for a large amount of values

I have about 20,000 records (coming from an SQLite db) that I need to present to the user for possible choices, so conventional picker control is out of question.
Another possibility could be an indexed UITableView where user could check the desired value, however keeping all the 20K records in the memory doesn’t seem like a good idea.
how should I go about implementing UI for it? EDIT: is it possible to do something like auto-complete combo-box?
I'd look at some sort of nested UI i.e. a UITableView that has just A, B, C etc to start with and when the user presses on a row show another table view with all the results starting with A.
There would need to be a query that got the number of results that started with A, B, C etc so you only showed letters in the first table that actually has results but then each query in the second table would be very simple - all results starting with 'A' etc.
You'd never have to load all 20,000 results into memory at the same time :)
However, you should probably make sure that you have an index on the field that you're querying, otherwise your queries are all going to be rather slow :(
The other solution is to use a search box at the top of a table view - the user types in letters and each time the list is reduced to only results starting with that letter. That's a pretty simple query to implement :)
However, you would then still have the problem of what to do if the user hasnt typed anything in - do you show a message asking them to type or do you show all 20,000 results in an enormous list?
Are you aware of UIPickerView's "components"? 20,000 choices might be pushing it, but it is certainly one way (that is familiar to users) to narrow down choices by an order of magnitude with each spin.
If you find yourself constrained in one dimension, you could implement master-slave picker views.