loading SQL rows into an indexed UITableView - iphone

I have about 2000 rows in a SQLite database. Each row has an integer ID and a string value. I'd like to populate them into a UITableView with an alphabetical index like the Contacts app does.
Is it feasible to achieve performance that's as good as the Contacts app without using CoreData, providing I don't need to re-implement everything that CoreData does for you (e.g. caching etc)?
I have tried to implement this using paging with 50 rows per page, and pre-load the next page in another thread when the tableview has scrolled past 25 rows. This works if the scrolling isn't very quick, but still lags when it's scrolled really quickly. I think the step to populate a temporary NSArray of 50 items is taking a long time.
Furthermore, this approach does not work very well for the index for the UITableView because the loading is done sequentially whereas the index skips. I thought about loading the first 10 rows for each index key at initialisation but again, it will be quite slow (populating an array with 260 items).
Any suggestions?

It looks like performance for fetching a few thousand rows at once should not be a big deal (You should just be able to pre-fetch them).
I would asynchronously run a SELECT on your table for whatever columns you want (like the index for reference and maybe just the string to be displayed) and throw them into an NSMutableDictionary keyed on the index and then reload the table data. The cellForRowAtIndexPath UITableViewDataSource function would use this dictionary.
If you allow users selecting a row to see details, you can then run a query for the rest of the data for that row upon selection.
Doing the initial fetch asynchronously in ViewDidLoad or ViewWillAppear will prevent the UI from locking up when the user goes to view the table and in almost all cases the table should already be visible once they actually see the table.
initial fetch(performed on a background thread, followed by the table reloading on the main thread)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^()
{
//perform your query here
dispatch_async(dispatch_get_main_queue(), ^()
{
[self.tableView reloadData]
});
});

i am taking example of A-Z only
take 26 section in table.
there will be 26 query for fetching data
first for starting with A
second is for starting with B
third is for starting with C...... and on upto Z
in cellForRowAtIndexPath().
till the user dont scroll the table it wont fetch data for other alpha bets.
if each From A to Z contain 100 name(text).
still it wont take too much time.
hope you can get idea from here..

Related

store selected rows on PFQueryTableViewController

I have a tableview that is of type PFQueryTableViewController and gets its value from Parse cloud. The tableview works fine but now I need to allow the user to:
Select a row
Record in a column (string array) on Parse-Users table what rows have been selected (need to record on parse that - i will use these values for other things later)
When the user comes back and opens the tableview he can see what rows have been selected last time he was in the app
I am not sure if PFQueryTableViewController has any methods ready for that. Could anyone give me some guidance?
I would prefer to use parse cause there are so much stuff out of the box. But if not, that is fine as well.
Also, code samples from similar solutions would be great. Just need to know the best approach.
The table view controller is there for display, it will tell you about selection, but it won't automatically maintain a record of selected items in the back end. You need to decide on the appropriate way to store the selections (array of pointers is better than an array of strings) and update the store and table display appropriately. There is no standard approach to this.

What's the best way to temporarily persist results of a long running SP?

I have a TSQL stored procedure that can run for a few minutes and return a few million records, I need to display that data in an ASP.NET Grid (Infragistics WebDataGrid to be precise). Obviously I don't want return all data at once and need to setup some kind of paging options - every time user selects another page - another portion of data is loaded from the DB. But I can't run the SP every time new page is requested - it would take too much time.
What would be the best way to persist data from the SP, so when user selects a new page - new data portion would be loaded by a simple SELECT... WHERE from that temp data storage?
A few options
One:
If the user only pages forward then you could just hold the connection open and use a DataReader. Just .Read() as needed.
Two:
Create a #temp table using the userID as part of the name to store the results. I don't like this as if user aborts sometimes tables are left over. About 1/2 second hit to create and drop the #temp. Store the entire results or just the PK and create the page detail on demand.
Three:
Use a DataReader to read the the PK into a List<>. It is faster than you would guess. That List is only going to IIS (not to the browser). List can be referenced by ordinal [] and preserves the sort. Get the detail for a page as required. The problem here is where PK in (3,9,2,6) will not return them in that order. I use TVP to pass the order, PK so the page is sorted by order. I do exactly this and get pages loads for objects with 20 properties 40 rows at a time and it takes less than 1/2 second. Do one query per table (NOT one per row) then assemble assign properties in .NET. Use DataReader (not DataTable). And you can even run the reader on a backgroundworker and pass back the first page of PKs using progresschanged.
Have you look at Server Side Paging (article is 2005, but will work with 2008 and CTEs). Also - just wondering, is there any reason you are returning that many rows? I can't see a very good use of a human paging through a million records even if the page size was 1000.

Obj-C, catering for 'tap for more rows' and delete without core data?

I've been adding a temporary row to the end of my table view so I can limit the amount of data loaded / improve the speed of loading the view.
However, I didn't think about the delete feature. Where they swipe right to delete a row..
In my commitEditingStyle event I have, my check to see if it is a delete, then delete row from database, removeObjectAtIndex from my data array, beginUpdates, deleteRowsAtIndexPaths and if zero items left in my table insertRowsAtIndexPath with fade, so that my no transactions row will appear then endUpdates.
I did think when I add my tap for more rows I'd assign the row index to a variable and delete this row first in the commitEditingStyle event. However, I'd then have to query my database just to add another row, then add the tap for more rows row.
Which seems a lot of work for a quick fix.
Of course, I could just do a reloadData, but this seems really bad, but might be my only option.
I do eventually want to move to Core Data, but I really need to get this release out the door, its quite a complicated screen with segmented control for different data views and tap to edit the row in another view.
Can anyone advise me about some kind of trick / event I may have missed or another approach I could quickly use in this scenario ?
Make "tap for more" your table footer view instead of another cell. You will have to do this anyway if you move to core data and NSFetchedResultsController since hacking in an extra row becomes very complex then.
Your table footer view will just be a button (or some other view styled how you like it) - this can be created on viewDidLoad and set up with actions etc. It does not form part of your data model at all, so you have nothing extra to do in your datasource methods.

Refreshing/releasing 2nd tableview from previous query in drill down tableview

I have a drill down tableview that is using sqlite.
The first one is a tableview where i load some categories using a SQL query.
When i click a row it's using the following query to show the appropriate records for the category:
#"SELECT * FROM table WHERE category IS ('%#')", sharedSingleton.category];
This works.
When i click the back button on tableview 2 and return to the category tableview and then touch another category tableview2 still shows the rows for the category i selected the first time.
I'm new to this stuff but i searched a long time and tried releasing objects or set value's to nil but is doesn't seem to help.
Am i in the right direction, how can i refresh or release tableview2?
Thanks in advance.
Yes you are in the right direction.
When selecting a row table 1 you might be calling a method which loads the second table view and assigning the data to be loaded to the corresponding table view,Which is fetched and filled when delegate/ data source methods of table view is called.
You might have created tableview as a different view controller class, which is initialized and data is reloaded for the first time. But even though you are fetching the second set of data its not getting reloaded automatically even after you are assigning it.
After assigning the data you have fetched into the obect which distributes it to tableview Reload the table data once you assign it to. you could call the one line of code to do this
[tableview reloadData];
Regards,
Jackson Sunny Rodrigues

iPhone:How do i insert few rows in the middle of existing table?

If i want to insert few rows in the middle of the existing table, how do i approach it? Where all that i should be careful when doing such thing? Is there any good sample source available?
Appreciate your helps.
Thank you.
Tableviews don't contain data and they don't actually contain rows themselves. Instead, tableviews are just an illusion created by redisplaying the same tableviewcell objects over and over again with different data each time. The real table, the real rows, are actually in the logical data.
So, to " insert few rows in the middle of the existing table" you actually add the rows into the data that the table displays. For example, if you had a simple array of names that you display in the table, you would insert the new names into the array. Then you would call -[UITableView reload] which will cause the table to ask the datasource for the new data.
See the Table View Programing Guide for iPhone OS.
Insert the data into your model and call reloadData on the table. If you need to animate the insertion for some reason, you can use insertRowsAtIndexPaths:withRowAnimation:, but the principle if updating the model first still applies.