最近公司要缓存数据,本来开始想使用FMDB的,但是公司项目是swift
的,而它是oc
的,leader
不同意,就推荐使用了CoreStore,它是swift
出的框架,最新的已经支持到swift 5.0
,它支持的版本有swift 3.2
,swift 4.0
,swift 5.0
,文档也是比较全面,但是确实英文的,不提了,我太难了。
本文章,只面向实战,并不对
CoreStore
里面的思想、模式、代码等做太多的解释。因为我也不懂,还没看。
image.png
我默认你已经会使用
cocopods
,安装第三方库了。
以及一些CoreData
的简单操作
NSPredicate
的操作,本文也会设计一些,但是不会很多
1.创建一个CoreStore
的数据库
create CoreData.png
剩下的就是创建你需要的表,以及创建里面的字段,再次都不一一列举,如果不会,请右转百度,左转谷歌
2.使用CoreStore
连接次数据库
2.1 初始化一个默认的
dataStore
,会默认创建一个默认的SQLiteStore
try? CoreStoreDefaults.dataStack.addStorageAndWait()
2.2,我们也是可以 自定义库的
/**
xcodeModelName: 表示本地CoreData的名称
bundle: 表示CoreData所在的bundle
*/
let dataStack = DataStack(xcodeModelName: "CoreStore", bundle: Bundle.main, migrationChain: [])
dataStack.addStorage(
/*
fileName 表示本地保存的sql的名称,默认是Target的名称
configuration CoreData的组
**/
SQLiteStore(fileName: "CoreStoreDemo.sqlite",configuration: "Default", localStorageOptions: .recreateStoreOnModelMismatch), completion: {_ in })
/// 将创建的stack赋值给全局变量,那样我们就可以在任何地方去使用了,而不用再次创建
CoreStoreDefaults.dataStack = dataStack
configuration 参数对应的数据
configuration.png
3.添加数据
数据的操作,
CoreStore
使用的是同个方法
/**
异步执行的方法
asynchronous: 里面去执行添加,更新,删除,查询等数据的操作
completion:是执行的操作,成功或者失败的后续,如果你不想判断成功或者失败,你就使用下面那个方法,此方法的内部也是调用了下面方法
*/
CoreStoreDefaults.dataStack.perform(asynchronous: nil, completion: nil)
CoreStoreDefaults.dataStack.perform(asynchronous: nil, success: nil, failure: nil)
/*
同步执行的操作
synchronous: 里面去执行添加,更新,删除,查询等数据的操作
waitForAllObservers: 是个bool值,默认是`true`,当为`true`的时候,表示会通知所有的监听者发生改变后,再回返回,也造成一定的死锁,当设置为`false`的时候,是不告诉监听着,直接返回,会降低一些死锁的方式
**/
CoreStoreDefaults.dataStack.perform(synchronous: nil, waitForAllObservers: Bool)
/// 方法一
/**异步执行,可以在里面创建,更新,删除操作**/
CoreStoreDefaults.dataStack.perform(asynchronous: { transaction in
let student = transaction.create(Into<Student>())
student.name = faker.name.name()
student.score = Int16(faker.number.randomInt())
student.grade = [Int16(1),Int16(2)].randomElement()!
}, completion: { _ in })
/// 方法二
/**同步执行,可以在里面创建,更新,删除操作,
waitForAllObservers,默认是true,会通知完所有的监听着,再返回,有可能会造成死锁(监听里面也更新等)。
如果为false,则不会通知监听着,直接返回,减小死锁的概率
**/
do {
try CoreStoreDefaults.dataStack.perform(synchronous: { (transaction) in
let student = transaction.create(Into<Student>())
student.name = faker.name.name()
student.score = Int16(faker.number.randomInt())
student.grade = [Int16(1),Int16(2)].randomElement()!
}, waitForAllObservers: false)
} catch let error {
print("waitForAllObservers:",error.localizedDescription)
}
4.查询数据
查询数据库,有以下两个方法,同样的使用的方法也是上面介绍的两个方法操作的
/// 查询符合条件的所有数据,返回的是个`Array`
transaction.fetchAll()
/// 查询符合条件的单个数据,返回的是一个单独的对象
transaction.fetchOne()
/// 查询所有的strudent
CoreStoreDefaults.dataStack.perform(asynchronous: { (transaction) in
let students = try transaction.fetchAll(From<Student>())
for student in students {
print("student.name:", student.name!,"student.score:", student.score)
}
}, success: { _ in }, failure: { _ in })
/// 查询单个的`Student`
CoreStoreDefaults.dataStack.perform(asynchronous: { (transaction) -> Student? in
let student = try transaction.fetchOne(From<Student>())
print("student.name:", student!.name!,"student.score:", student!.score)
return student
}) { (result) in
switch result {
case .success(let student):
print("success,student.name:", student!.name!,"student.score:", student!.score)
case .failure(let error):
print("completion error :",error.localizedDescription)
}
}
4.1.条件where
语句的查询
CoreStore
是封装与CoreData
的,所以使用的是NSPredicate
来当条件语句查询的
where 基本介绍
and
或&&
且的关系or
或||
或的关系not
或!
非的关系
/// 下面这几种写法都是可以的,其实Where的本质还是封装的NSPredicate
/// 简单介绍一些 %K 表示 key, %@表示value
/// 相当于 name = Katlynn Dickens
let predicate = NSPredicate(format: "%K = %@", "name", "Katlynn Dickens")
let student = try transaction.fetchOne(From<Student>(), Where<Student>(predicate))
let student = try transaction.fetchOne(From<Student>(), Where<Student>("%K = %@", "name", "Katlynn Dickens"))
let student = try transaction.fetchOne(From<Student>().where(format: "%K = %@", "name", "Katlynn Dickens"))
4.2 排序
排序使用的关键词是
orderBy
.descending(\.score)
根据score
倒序排序
.ascending(\.score)
根据score
正序排序
let students = try transaction.fetchAll(From<Student>().orderBy(.ascending(\.score)))
let students = try transaction.fetchAll(From<Student>().orderBy(.descending(\.score)))
4.3分页查询
分页查询可是使用
tweak
配合fetchLimit 和 fetchOffset
来使用
/// fetchLimit 查询多少条
/// fetchOffset 间隔多少条,开始取值
let students = try transaction.fetchAll(From<Student>().orderBy(.descending(\.score)).tweak {
$0.fetchLimit = 1
$0.fetchOffset = 2
})
4.4 Select
的使用
- 当我们只需要一条数据中某一个属性值的时候,你还在
fetchOne
来获取数据,拿取值嘛?其实不需要。我们可以使用queryValue
配合select
即可- 当我们需要一些原始属性的时候,我们可以使用
queryAttributes
配合select
来获取原始属性数组select
都是可以可以配合where
、orderBy
、tweak
、GroupBy
配合使用到,再次都不一一列举了。
/// 当我们只需要一个参数值的时候,可以使用此方法
try CoreStoreDefaults.dataStack.queryValue(From<Student>(), Select<Student,Int16>("score"))
/// 在此方法上面我们还可以使用一些聚合函数
try CoreStoreDefaults.dataStack.queryValue(From<Student>(), Select<Student,Int16>(.count("score")))
/// 获取原始属性,只有name,score连个属性
/// 返回是一个包含符合条件的`字典数组`
try CoreStoreDefaults.dataStack.queryAttributes(From<Student>().select(Select("name", "score")))
//// 同样的再次方法里面我们也可以使用聚合函数
/// 并且使用了聚合函数的别名 as:
try CoreStoreDefaults.dataStack.queryAttributes(From<Student>().select(Select("name", .average("score", as: "scoreSum"))))
聚合函数,注意:我们可以使用
as:
来个聚合函数别名
.average
平均数.sum
和count
个数maximum
最大值minimum
最小值
注意,以上的orderBy
分页
、select
都是可以使用类似where
的其他写法,再次都不一一列举