在iOS中,使用未经处理的SQLite库是一件很痛苦的事情,所以出现了很多封装后的库,其中在Swift语言中使用的较为广泛的库是SQLite.Swift。使用过的都知道,这个库很好,但是不支持模型化转换就很苦恼,正因为如此,本文所写的也正是对SQLite.Swift的模型化封装

使用

  1. 创建的模型实现SQLiteProtocol协议即可
1
2
3
4
import SQLiteManager

class TestModel: NSObject, SQLiteProtocol {}
struct TestModel: SQLiteProtocol {}
  1. 创建模型后即可快速开始数据库操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// 插入模型(默认不存在会创建
SQLiteManager.default.insert(testModel)

/// 删除模型
SQLiteManager.default.delete(testModel)

/// 更新模型数据
testModel.name = "Ree"
testModel.create_time = Int(Date().timeIntervalSince1970)
SQLiteManager.default.update(testModel)

/// 查询模型数据
let arr = SQLiteManager.default.select(TestModel.tableName)
let models = arr.map({ TestModel.deserialize(from: $0) })
print("查询到数据: \(models)")

/// 删除数据表
SQLiteManager.default.drop(TestModel.tableName)

以下是实现原理,若想直接使用,请直接访问Github,或者直接pod安装

1
pod 'JXSQLiteManager'

基础协议

首先我们需要准备一个通用的协议来规定一些通用的属性,以及转模型时需要的初始化方法。后续所有的模型都是实现该协议来实现

1
2
3
4
5
6
7
8
9
10
11
public protocol SQLiteProtocol {
static var tableName: String { get }
/// 主键字段
var primaryKey: String? { get }
/// 忽略的字段,不保存
var ignoreKeys: [String]? { get }
/// 唯一的字段
var uniqueKeys: [String]? { get }

init(_ dict: [String: Any])
}

声明属性模型

有了基础协议后,我们还需要一个模型来保存反射解析出的属性列表来记录当前模型有哪些数据表属性

1
2
3
4
5
6
7
8
9

public struct SQLitePropModel {
public var key: String
public var value: Any
/// 是否是主键
public var primary = false

private var option = false
}

通过反射获取每一列的属性,可选类型(optional)在数据表中即为非必填项,并且当属性值为nil时记录值为空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public init(_ key: String, value: Any, primary: Bool) {
self.key = key
self.primary = primary

let mirror = Mirror(reflecting: value)
self.option = mirror.displayStyle == .optional
// unwrap optional
if mirror.displayStyle != .optional {
self.value = value
}else if mirror.children.count == 0 { self.value = "" }
else {
let (_, some) = mirror.children.first!
self.value = some
}
}

支持的数据类型对应数据库类型如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public var datatype: String {
let nativeType = type(of: value)
var datatype = ""

if nativeType is Int.Type || nativeType is Int?.Type {
datatype = "INTEGER"
}else if nativeType is Float.Type || nativeType is Double.Type || nativeType is Float?.Type || nativeType is Double?.Type {
datatype = "REAL"
}else if nativeType is NSString.Type || nativeType is String.Type || nativeType is Character.Type || nativeType is NSString?.Type || nativeType is String?.Type || nativeType is Character?.Type {
datatype = "TEXT"
}else if nativeType is Bool.Type || nativeType is Bool?.Type {
datatype = "REAL"
}else{
assert(true, "sqlType:不支持的类型")
}
return datatype
}

获取模型属性

通过数据模型反射出对应的数据表属性模型列表,在该方法中处理需要忽略的模型字段以及模型属性列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// 反射保存属性的model
public struct SQLMirrorModel {
public static func operateByMirror(object: SQLiteProtocol) -> SQLMirrorModel {
let mirror = Mirror(reflecting: object)
var props = [SQLitePropModel]()
for case let (key?, value) in mirror.children {
let model = SQLitePropModel(key, value: value, primary: object.primaryKey == key)
if object.ignoreKeys?.contains(key) == true {
continue
}
props.append(model)
}

if mirror.displayStyle != .class || mirror.displayStyle != .struct {
assert(true, "operateByMirror:不支持的类型")
}
return SQLMirrorModel(type(of: object).tableName, props: props, primaryKey: object.primaryKey)
}
}

多有不足,敬请指教👻