FMDB 中的 moveToRow() 和 rowCount()?

发布于 2024-12-12 03:01:12 字数 945 浏览 0 评论 0原文

我的应用程序的 .sqlite 文件中有 3,000 个考试题。并且这些问题是根据用户的需求动态选择和排序的(例如,“按错误答案的数量排序”、“仅选择未访问的问题”)。

每当用户做出选择时,应用程序都会生成相应的 SQL 语句,并使用 sqlite3 将所有结果集发送到 NSMutableArray(问题类)中。但正如您将注意到的,这是一个耗时的过程(大约 2~3 秒,并且 UI 在此过程中停止响应)。

所以我想创建一个具有 rowCount() 和 moveToRow(int index) 方法的“光标”类。

有了这个,我的想法是

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);
}

这样的。

我知道 CoreData 适合这个目的,但我需要与这个应用程序的 Android 版本共享 .sqlite 文件。 CoreData 要求所有表名和字段名以 Z_ 前缀开头,但我无法修改 .sqlite 文件的方案。我还需要使用 sqlcipher,而 CoreData 不能与 sqlcipher 一起使用。

FMDB 不支持提供检索行数并移动到特定行的方法。

是否有其他 SQLite 包装器库支持此功能?

有人建议创建一个“目录”数组,其中仅包含检索到的行的 id,并在每次调用 moveToRow() 时获取行。我同意这是一个很好的选择,但我想找到另一种方法。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

国粹 2024-12-19 03:01:12

另一种方法可能会将您的查询限制为 1 行数据。即在 cellForRowAtIndex 处进行调用。根据我的经验 - 最好有一个单独的方法 -
如果确实需要,您甚至可以更进一步,添加一个 DataCache 层,用于根据 coredata 缓存到内存。

像这样的东西......
http:// /code.google.com/p/airband/source/browse/trunk/airband/Classes/DataCache.h?spec=svn103&r=103

例如。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//初始化你的单元格,

 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;
}

检查我的 EgoDatabase 分支。
https://github.com/jdp-global/egodatabase

它还包括非异步方法阻塞。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文