My app has 3,000 exam questions in .sqlite file. And these questions are dynamically selected and sorted by user's demand (for example, 'sort by count of wrong answer', 'select non-accessed questions only').
Whenever user makes a selection, app makes corresponding SQL statement and by using sqlite3, all the result sets are sent into NSMutableArray(Question class). But as you will note, this is time-consuming process (about 2~3 secs and UI stops responding while doing so).
So I want to make a 'cursor' class which has rowCount() and moveToRow(int index) methods.
With this, my idea is
Cursor c = [[Cursor alloc] init] query(
"SELECT id,qtext,answer,a1,a2,... FROM TABLE WHERE id > 100"
)];
// at this time, just a cursor is given, no need to iterate all the retrieved rows
for (i=0; i > c.rowCount(); i++) {
c.moveToRow(i);
ShowQuestionDetail(c);
}
Like this.
I know that CoreData fits this purpose, but I need to share .sqlite file with android version of this app. CoreData requires all the table names and field names start with Z_ prefix, but I can't modify schemes of the .sqlite file. Also I need to use sqlcipher, and CoreData doesnt work with sqlcipher.
FMDB doesn't support methods that gives count of retrieved rows and move to specific row.
Is there any other SQLite wrapper libraries which supports this functionality?
Someone suggests making an 'catalog' array which only contains id of the retrieved rows, and fetch row each time when moveToRow() called. I agree that's an good alternative, but I want to find another way.
Another approach maybe to limit your query to 1 row of data. That is make the call at cellForRowAtIndex. From my experience - it's better to have a separate method for this - you could even go one step further and add a DataCache layer for caching to memory as per coredata if you really needed to.
Something like this .... http://code.google.com/p/airband/source/browse/trunk/airband/Classes/DataCache.h?spec=svn103&r=103
Eg. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //init your cell
NSDictionary *dict = [self questionDataForCellAtIndexPath:indexPath];
// set the cell values
}
-(NSDictionary*)questionDataForCellAtIndexPath:(NSIndexPath *)indexPath{
//ENTER_METHOD;
NSDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:0];
NSString *qry = [NSString stringWithFormat: @"SELECT id,qtext,answer,a1,a2,... FROM TABLE WHERE id ORDER BY id DESC limit 1 offset %d", [indexPath row]];
// you could look up here for previously accessed rows from DataCache
// NSDictionary *cachedRow = [DATAENV.cache objectForKey:num];
///if (cachedRow == nil) {
// go get it
// else return it
DLog(@"qry%@",qry );
EGODatabaseResult *result = [appDelegate.userdb executeQuery:qry];
if ([result count]==0) {
return dict;
}
for(EGODatabaseRow *row in result) {
[dict setValue:[row stringForColumn:@"name"] forKey:@"name"];
}
return dict;
}
check out my fork for EgoDatabase. https://github.com/jdp-global/egodatabase
it also includes asynchronous methods that are non blocking.