You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:33:23