Swift 模型化使用SQLite3

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

使用

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

class TestModel: NSObject, SQLiteProtocol {}
struct TestModel: SQLiteProtocol {}
  1. 创建模型后即可快速开始数据库操作
/// 插入模型(默认不存在会创建
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安装

  pod 'JXSQLiteManager'

基础协议

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

public protocol SQLiteProtocol {
    static var tableName: String { get }
    /// 主键字段
    var primaryKey: String? { get }
    /// 忽略的字段,不保存
    var ignoreKeys: [String]? { get }
    /// 唯一的字段
    var uniqueKeys: [String]? { get }
    
    init(_ dict: [String: Any])
}

声明属性模型

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


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

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

    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
        }
    }

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

    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
    }

获取模型属性

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

/// 反射保存属性的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)
    }
}

多有不足,敬请指教👻

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354