使用Xcode添加预加载SQLite数据库到iOS App后提示表不存在
嘿,我来帮你搞定iOS里打包预加载SQLite数据库并通过FMDB访问的事儿,这流程我熟得很,一步步来:
打包并访问预加载SQLite数据库(iOS + FMDB)
第一步:把数据库文件加入Xcode项目
- 直接把
myDB.dms拖拽到Xcode的Project Navigator窗口里 - 弹出的对话框里一定要勾选「Copy files if needed」,同时别忘了选中你的App target(不然文件不会被打包进Bundle里)
- 稳妥起见,去项目的
Build Phases->Copy Bundle Resources里确认下,myDB.dms是不是在列表里,避免漏加导致后续找不到文件
第二步:用FMDB实现数据库操作类
核心提醒:Bundle里的文件是只读的!所以第一次启动App时,必须把数据库复制到Documents目录(可读写区域),之后所有操作都针对Documents里的副本。
下面是你提到的三个核心方法的具体实现思路和代码:
1. copyDB 方法:复制数据库到可读写目录
先检查Documents里有没有现成的数据库,没有的话再从Bundle复制,避免重复操作:
- (void)copyDB { // 获取Bundle里的源DB路径 NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"myDB" ofType:@"dms"]; // 获取Documents目录的目标路径 NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *targetPath = [docsDir stringByAppendingPathComponent:@"myDB.dms"]; // 检查目标路径是否已存在DB文件 NSFileManager *fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath:targetPath]) { NSError *error = nil; // 复制文件 BOOL success = [fileManager copyItemAtPath:sourcePath toPath:targetPath error:&error]; if (!success) { NSLog(@"复制数据库失败:%@", error.localizedDescription); } } }
2. openDB 方法:打开Documents里的可读写数据库
先调用copyDB确保文件已就位,再用FMDB打开目标路径的数据库:
#import "FMDatabase.h" @interface DBManager () @property (nonatomic, strong) FMDatabase *db; @end @implementation DBManager - (BOOL)openDB { // 先确保DB已经复制到可读写目录 [self copyDB]; NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *dbPath = [docsDir stringByAppendingPathComponent:@"myDB.dms"]; self.db = [[FMDatabase alloc] initWithPath:dbPath]; if ([self.db open]) { NSLog(@"数据库打开成功"); return YES; } else { NSLog(@"数据库打开失败:%@", self.db.lastError.message); return NO; } }
3. executeQuery 方法:执行查询操作
基于打开的FMDatabase实例,封装通用查询方法,比如把查询结果转成字典数组返回:
- (NSArray *)executeQueryWithSQL:(NSString *)sql arguments:(NSArray *)arguments { if (!self.db || ![self.db isOpen]) { // 如果DB没打开,先尝试重新打开 if (![self openDB]) { return nil; } } FMResultSet *resultSet = [self.db executeQuery:sql withArgumentsInArray:arguments]; NSMutableArray *results = [NSMutableArray array]; while ([resultSet next]) { // 把每行数据转成字典,可根据你的表结构调整字段处理逻辑 NSMutableDictionary *row = [NSMutableDictionary dictionary]; for (NSString *columnName in resultSet.columnNames) { id value = [resultSet objectForColumnName:columnName]; row[columnName] = value ?: [NSNull null]; } [results addObject:row]; } [resultSet close]; return results; }
几个关键注意事项
- 绝对不要直接操作Bundle里的数据库,因为Bundle是只读区域,写入操作会直接失败
- 可以在
DBManager的初始化方法里调用openDB,确保第一次使用数据库时就已经完成复制和打开操作 - 如果后续需要更新数据库版本,可以在
copyDB里加版本判断逻辑(比如对比Bundle和Documents里DB的版本号),需要更新时替换旧文件
内容的提问来源于stack exchange,提问作者Rookie
相关产品推荐
相关产品推荐

