iOS Swift 简单封装实现 Model 自动映射本地数据库及更新表结构

1,367 阅读4分钟

废话开篇:移动端本地数据库一般会在存储数据列表的时候用到,可以用本地数据库单纯的进行无网络状态下的缓存展示。下面的的数据库用的是 FMDB 解析数据用的是 SwiftyJSON,本来打算用 RealmSwift,看它的资料里面的就是直接 model 进行映射的,很是直观,不过最新版本的一直报引用依赖库找不到的错,低版本 cocopods 又安装不上,大神如果知道怎么解决的给个提示。那么,就按照个人思路去实现一个这样的小工具类。

一、怎么设计?

设计的整体思路就是动态的获取结构体里面的成员 keyvalue,配合 FMDB 灵活的进行数据库 columnkeyvalue 的修改,在结合 SwiftyJSON 进行 model 对象初始化赋值。

二、最后实现效果

1、插入

数据源

image.png

动态插入

image.png

打印如下

image.png

2、查询

image.png

打印如下

image.png

3、删除

image.png

打印如下

image.png

4、更新表结构

image.png

比如 WSLChanneSubModel 结构体新增一个 country 字段,然后把 version12 改为 13

image.png

打印如下

image.png

前面的 Int 类型的参数代表的是版本,其实内部本身就能对自身检查更新,这里就仅作为版本记录,比如:某个表的更新版本低于传入的版本号就进行更新,并记录当前更新完版本号。

三、封装结构体,实现动态获取成员值操作

这里可能会有疑问了,Swift 里面不是有 KVC 吗?为什么还要封装?

Class 对象类型下,并且它里面的属性用 @obj 修饰的是可以用 KVC

方式 1#keyPath

image.png

方式 2"key"

image.png

struct 结构类型下,可以用 KVC

方式 1、 keyPath

image.png

方式 2、 Mirror 映射类

image.png

因为结构体类型的数据占有内存更少,读取性能更好,所以,这里就用 Mirror 映射类进行结构体数据的 键-值 读取。

1、声明结构体可数据库操作读写的属性类型枚举 WSLGetModelPropertyType

image.png

声明这个枚举的目的即舍得能够进行数据库操作的属性类型,并且将属性的 keyvalue 作为枚举的关联值。

2、声明 WSLParseable 协议,实现公共方法

image.png

3、扩展 WSLParseable 协议实现内部方法

扩展 getPropertyType 方法,返回 WSLGetModelPropertyType 枚举,将结构体下的值包裹成 WSLGetModelPropertyType 枚举值

image.png

扩展 getAllProperty 方法,返回 Dictionary ,将结构体下的值根据类型进行数据库字段格式绑定

image.png

扩展 getValue 方法,实现通过 keyName 字符串取值

image.png

4、声明 WSLChanneSubModel 遵循 WSLParseable 协议

image.png

WSLChanneSubModel 类就是后面要自动映射的数据库的类

四、声明 WSLDBManager 数据库操作类

1、声明 TableOptionType 枚举类

描述:对应结构体下的数据库判别需要操作类型的枚举,因为本地会保存结构体对应数据表版本号,那么,通过此版本号可以进行是否需要新建、更新等操作

image.png

2、声明 WSLDBManager 类,动态数据库操作的工具类
2-1 伪单例实现:

image.png

2-2 声明 judgetCurrentTableIfNeedOption 方法

判断某一结构体 model 类对应本地数据表待操作类型

image.png

此方法返回了一个元组,参数为 TableOptionType 和一个暴露给外界同步数据表版本的闭包(当数据库操作完成之后执行)。

2-3 声明 updateDBTable 方法

通过返回元组里面的 TableOptionType 值进行数据表具体操作

image.png

2-4 声明 dynamicCreateDBTable 方法,实现动态创建数据表

实现动态创建表,并返回是否创建成功

image.png

这里可以看到 T 类型结构体调用了 getAllProperty 方法,获取里面的每个 key 值对应的数据库属性值。例如 (name : TEXT)

同时调用外界传进来的 callBack 方法,如果数据库操作成功后就进行执行闭包同步表版本操作

2-4 声明 dynamicAddDBTableColumn 方法,实现动态修改表结构

image.png

同样是调用 getAllProperty ,在遍历后对表里面字段进行判断,如果 column 没有,那么就去新建一个 名字为 keycolumn

同时调用外界传进来的 callBack 方法,如果数据库操作成功后就进行执行闭包同步表版本操作

2-5 声明 dynamicInsertTTypeModel 方法,实现动态插入数据

image.png

image.png

sql 语句用 getAllProperty 方法获取 struct 下的属性列表,并进行拼接操作。

2-6 声明 dynamicGetTTypeModel 方法,实现动态获取对应表下面的数据集合

image.png

表里取出的值被拼接为 json 格式的字符串,然后创建的时候以 init(json: JSON) 初始化方法进行初始化。

2-7 声明 dynamicDeleteTTypeModel 方法,实现动态删除对于表下面的全部数据

image.png

五、总结与思考

上面的内容其实就是一个思路,肯定有瑕疵,欢迎讨论,对于 RealmSwift 类报找不到 Realm.sync 库找不到的问题,还请大神能给予小小的帮助。代码拙劣,大神勿笑。