在iphone SQLite(FMDB)中加载10k +行

时间:2011-09-26 08:16:48

标签: iphone sqlite optimization fmdb

我正在创建一个字典应用程序,我正在尝试将这些术语加载到iphone字典中以供使用。这些术语是从该表(SQLite)中定义的:

id -> INTEGER autoincrement PK 
termtext -> TEXT
langid -> INT
normalized -> TEXT 

使用Normalized是因为我在GREEK中写作而且我在sqlite引擎上没有用于搜索变音符号的icu,所以我正在制作一个termtext diacritics / case insensitive。它也是主要的搜索字段,与termtext相反,后者可能是“视图”字段。

我已经定义了一个类(如POJO):

terms.h

#import <Foundation/Foundation.h>
@interface Terms : NSObject {
 NSUInteger termId; // id
 NSString* termText; // termtext
 NSUInteger langId; // langid
 NSString* normalized; // normalized
}
@property (nonatomic, copy, readwrite) NSString* termText;
@property (nonatomic, copy, readwrite) NSString* normalized;
@property (assign, readwrite) NSUInteger termId;
@property (assign, readwrite) NSUInteger langId;
@end

terms.c

#import "Terms.h"

@implementation Term
@synthesize termId;
@synthesize termText;
@synthesize langId;
@synthesize normalized;
@end

现在在我的代码中,我使用FMDB作为SQLite数据库的包装器。我使用以下代码加载术语:

[... fmdb defined database as object, opened ]
NSMutableArray *termResults = [[[NSMutableArray alloc] init] autorelease];
FMResultSet *s = [database executeSQL:@"SELECT id, termtext, langid, normalized FROM terms ORDER BY normalized ASC"];
while ([s next]) {
 Term* term = [[Terms alloc] init];
 term.termId = [s intForColumn:@"id"];
 [... other definitions]
 [termResults addObject:term];
 [term release];
}

然后将整个termResults加载到UITableView(在viewdidload上),但每次启动应用程序时加载最多需要5秒。有没有办法加快这个过程?我已将id,termText编入索引,并在SQLite上进行了规范化。

***更新:添加了cellForRowAtIndexPath ****

[.. standard cell definition...]
// Configure the cell
Term* termObj = [self.termResults objectAtIndex:indexPath.row];
cell.textLabel.text = termObj.termText;
return cell;

3 个答案:

答案 0 :(得分:2)

由于你似乎无论如何都要将整个数据库加载到内存中(而且认为它是必须的),使用SQLite的重点几乎已经消失。

因此,如果数据是静态(不会更改),我会将数据库转换为对象一次,然后序列化对象(实现NSCoding协议)并存储此数组(或者更好,字典)使用writeToFile:atomically:。获得该文件后(在开发期间执行此操作),您可以在运行时使用arrayWithContentsOfFile:轻松加载它,在这种情况下应该更快。

答案 1 :(得分:1)

将大量数据加载到您的应用中需要时间。最好的方法是将数据从db加载到主应用程序线程的单独线程上。在加载每个项目时,将消息发回主线程以将项目添加到支持表格视图的阵列中。这样,您的应用加载时间将很短,并且您的UI将在数据从数据库加载时响应。这是基本的想法:

NSMutableArray *termResults = [NSMutableArray array];

// Load each item from the db on a separate thread using a block
dispatch_queue_t globalQueue = dispatch_get_global_queue();

dispatch_async(globalQueue, ^() {

  // Init the database
  ...
  // Load the items from the db
  FMResultSet *s = [database executeSQL:@"SELECT id, termtext, langid, normalized FROM    terms ORDER BY normalized ASC"];

  while ([s next]) {

    Term* term = [Term new];
    term.termId = [s intForColumn:@"id"];

    // Add the loaded item to termResults on the main thread
    // and refresh the table view
    dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();

    dispatch_async(mainDispatchQueue, ^() {
      // Add the loaded item to termResults
      [termResults addObject:term];
      // Refresh the table view. This will only reload the visible items.
      [tableView reloadData];
    });

    [term release];
  }
});

希望这有帮助。

答案 2 :(得分:0)

从sqlite读取10K记录到UITableView不是问题。首先,我看不出这样做的理由。其次,由于大量的内存分配,你无法避免时间差。内存分配是一个系统调用。系统调用通常很慢。在加载期间,ios会发送内存警告以运行应用程序,从而导致更长的间隙。如果你需要一百万条记录,你会怎么做? sqlite用于完全避免这种内存数据结构。如果你在iphone(icu)上的sqlite中看到使用unicode的问题 - 请阅读here。我在我的几个应用程序中使用了这个技术,所有这些都被批准了AppStore而没有任何问题。