集成WCDB的问题分析与解决

490 阅读4分钟

image.png

一、提示“Objective-C++ environment is required”

  1. 原因是:未将WCTTableCoding的协议写在.mm文件中

  2. 解决方案:由于WCDB是基于Objective-C++,因此需要将引用WCDB的源文件后缀 .m 改为 .mm

  3. 通过仔细阅读官方文档,已经说明我们在引用WCDB的时候,一定要注意引用的位置。

    1. 一种情况是可以通过一个头文件来统一声明项目中所有需要用到WCDB的数据模型的属性声明,但是属性绑定必须要在.mm文件中,并且在对应的数据模型中引用统一声明的头文件。 image.png image.png
    2. 另一种情况是每个数据模型独立声明,这样需要在.mm文件中再次@interface并绑定WCTTableCoding协议

二、提示“Library not loaded: @rpath/.framework/

  1. 原因是:library search paths是空的,缺少路径地址
  2. 解决方案是:在其里面增加$(inherited),clean项目

三、集成流程

  1. Podfile
platform :ios, '13.0'
use_frameworks!// 这个是必要条件
target 'Sample' do
    pod 'WCDB.objc'
end
  1. 可以在上述第一个问题中选择任意一种方式进行模型绑定,具体操作如下:

在项目中使用 Cocoapods 生成的 .xcworkspace 文件打开工程,并在需要使用 WCDB Objc的源代码文件头通过 #import <WCDBObjc/WCDBObjc.h> 引入即可。由于WCDB是基于Objective-C++,因此需要将引用WCDB的源文件后缀 .m 改为 .mm

  1. 创建数据库与表
// 创建数据库对象
WCTDatabase* database = [[WCTDatabase alloc] initWithPath:@"~/Intermediate/Directories/Will/Be/Created/sample.db"];
// 创建数据库表
BOOL ret = [database createTable:@"sampleTable" withClass:Sample.class];
  1. 操作数据
// 增
BOOL ret = [database insertObject:object intoTable:@"sampleTable"];
// 删
BOOL ret = [database deleteFromTable:@"sampleTable"];
// 改
BOOL ret = [database updateTable:@"sampleTable" setProperties:Sample.allProperties
            toObject:object];
// 查
NSArray<Sample*>* objects = [database getObjectsOfClass:Sample.class fromTable:@"sample_insert"];

四、补充说明

  1. 打开数据库

    1.     延迟初始化是 WCDB 的原则之一,绝大部分数据只会在需要用到时才创建并初始化。数据库的打开就是其中一个例子。
  2. 数据库会在第一次进行操作时,自动打开并初始化。开发者不需要手动调用

  WCTDatabase* database = [[WCTDatabase alloc] initWithPath:filePath];
  NSLog(@"%d", database.isOpened); // 输出 0
  BOOL ret = [database createTable:@"sampleTable" withClass:Sample.class];// 数据库此时会被自动打开
  NSLog(@"%d", database.isOpened); // 输出 1

  同时,也可以通过 canOpen 接口测试数据库能否正常打开。

  WCTDatabase* database1 = [[WCTDatabase alloc] initWithPath:filePath];
  NSLog(@"%d", database1.isOpened); // 输出 0
  NSLog(@"%d", database1.canOpen);  // 输出 1。仅当数据库无法打开时,如路径无法创建等,该接口会返回 NO
  NSLog(@"%d", database.isOpened);  // 输出 1
  WCTDatabase* database2 = [[WCTDatabase alloc] initWithPath:filePath];
  NSLog(@"%d", database2.isOpened); // 输出 1。WCDB 同一路径的数据库共享数据和状态等。
  1. 关闭数据库

    1.     与打开数据库相对应,关闭数据库一般情况下也不需要开发者手动调用。当某个路径的WCTDatabase已经完全dealloc时,数据库会自动关闭,并回收内存。
@autoreleasepool {
  WCTDatabase* database1 = [[WCTDatabase alloc] initWithPath:filePath];
  BOOL ret = [database1 createTable:@"sampleTable" withClass:Sample.class];// 数据库此时会被自动打开
  NSLog(@"%d", database1.isOpened); // 输出 1
}// 作用域结束,database1 dealloc、关闭数据库并回收内存
WCTDatabase* database2 = [[WCTDatabase alloc] initWithPath:filePath];
NSLog(@"%d", database2.isOpened); // 输出 0。
WCTDatabase* database1 = [[WCTDatabase alloc] initWithPath:filePath];
@autoreleasepool {
  WCTDatabase* database2 = [[WCTDatabase alloc] initWithPath:filePath];
  BOOL ret = [database2 createTable:@"sampleTable" withClass:Sample.class];// 数据库此时会被自动打开
  NSLog(@"%d", database2.isOpened); // 输出 1
}// 作用域结束,database2 dealloc,但 database1 仍持有该路径的数据库,因此不会被关闭。
NSLog(@"%d", database1.isOpened); // 输出 1。

  同时,也可以调用 close 接口,手动关闭数据库。

WCTDatabase* database = [[WCTDatabase alloc] initWithPath:filePath];
NSLog(@"%d", database.canOpen);  // 输出 1
NSLog(@"%d", database.isOpened); // 输出 1
[database close];
NSLog(@"%d", database.isOpened); // 输出 0

WCDB 也提供了 blockadeunblockadeisBlockaded 接口用于分步执行关闭数据库操作,可参考[相关接口文档][Swift-API-Reference-Close-OnClosed]

  1. 关闭数据库与线程安全

    1.     某些情况下,开发者需要确保数据库完全关闭后才能进行操作,如将数据库整体zip打包发送。
    2.     数据库是二进制文件,zip打包的过程中若数据发生了变化,则打包后的文件数据可能会不完整、损坏。因此,WCDB 提供了 close: 接口。
[database close:^{
  //执行独占的数据库操作,如zip压缩打包
}];

  在 close:的回调范围 block 内,可确保数据库完全关闭,不会有其他线程的数据访问、操作数据库,因此可以安全地操作文件。

  1. 内存回收

  purge 接口用于回收暂不使用的内存,主要是关闭闲置的数据连接。

  // 回收 database 数据库中暂不使用的内存 [database purge];

  // 回收所有已创建的数据库中暂不使用的内存

  [WCTDatabase purgeAll];

在 iOS 平台上,当内存不足、收到系统警告时,WCDB 会自动调用 [WCTDatabase purgeAll] 接口以减少内存占用。

  1. 数据库的文件操作
// 获取所有与该数据库相关的文件路径
NSLog(@"%@", [database paths]);
// 获取所有与该数据库相关的文件占用的大小
[database close:^{  // 数据库未关闭状态下也可获取文件大小,但不够准确,开发者可自行选择是否关闭  NSLog(@"%lu", [database getFilesSize].value());
}];
// 删除所有与该数据库相关的文件
[database removeFiles];
// 将所有与该数据库相关的文件移动到另一个目录
[database moveFilesToDirectory:otherDirectory];