1

其实我在segmentfault 上已经写过好几篇关于CoreData 的一些介绍了。大家好像一直都对 CoreData 没有什么好感,我一开始接触它呢仅仅是因为我什么都不懂,只知道有这么一个东西可以持久化存储东西,然后就开始学写了。学着学者就会发现,额,好像上手起来不是那么的简单哦。去Google 一圈发现,大家对这个东西吐槽挺多的么。看来也不是我一个人觉得难了!

后来呢有一段时间了解到 Realm 这么一个专门针对移动端持久化存储的方案,嗯上手起来确实很快。认真的看一遍教程,基本上就可以立马上手了。当然它也有它所存在的问题,如果你能接受App 体积增大一点点的话使用它也不是什么问题。性能 Realm 说是比 CoreData 性能高多少多少,额,我觉得把一般的 App 使用哪一个都可以吧,如果真的数据量特别大,对性能要求特别高的话,那你还真需要对比对比了。

那今天呢,我主要是想推荐两个库。QueryKitDATAStack ,这两个库呢我觉得使得我们使用 CoreData 更加的简单,更加的 Swifty。

QueryKit 从名字就可以看出来,它主要是用来负责我们的查询的。

DATAStack 你也可以从名字上猜出来是用来负责我们的 CoreData Stack。

这篇文章呢主要想给大家展示一下这两个库的给我们带来的方便性。其实呢你可以直接去看这两个库的 readme 文件,不想看我逼叨叨的话可以直接跳过下边内容了。之后有时间的话,我会写两篇文章来分析一下它们的源码。

在这里呢,我直接就贴出一个 NSManagedObject 子类,就不贴出 xcdatamodeld 里的东西了。

class User: NSManagedObject {
    @NSManaged var email: String
    @NSManaged var name: String
}

很简单,就两个属性。

接下来,我们对这个类扩展一些东西,方便我们使用。如果你使用过 CoreData 的话,估计会记得实例化一个 entity 的时候会让我们填写 entity name ,那是一个字符串,我们经常可能会写错。我们可以把它作为一个静态属性,这样的话我们可以直接通过 . 语法来调用,岂不是错误会降低很多。

extension User: ManagedObjectType {
    static var entityName: String { return "User"}
}

上边这一步呢,其实是我自己喜欢做的。和这两个库没有什么关系

DATAStack

DATAStack helps you to alleviate the Core Data boilerplate. Now you can go to your AppDelegate remove all the Core Data related code and replace it with an instance of DATAStack

我们可以非常简单的初始化一个 DATAStack 通过你的 Core Data Model name (xcdatamodel).

let dataStack = DATAStack(modelName:"MyAppModel")

对的,你没有看错。就仅仅只需要一行,你就完成了一个 CoreData Stack。

这个 Stack 帮我们维护两个上下文,Main Thread NSManagedObjectContextBackground Thread NSManagedObjectContext

Getting access to the NSManagedObjectContext attached to the main thread is as simple as using the mainContext property.

那么我们想获取到主线程的上下文你只需要使用

dataStack.mainContext 或者是 dataStack.viewContext, 这两个表示的都是 主线程中的 上下文

You can easily create a new background NSManagedObjectContext for data processing. This block is completely asynchronous and will be run on a background thread.

我们通常会将一个写入数据的操作放在一个后台线程中,你可以很方便的在一个闭包中完成所有这些异步操作,从而不会影响到你的主线程。

func createUser() {
    self.dataStack.performInNewBackgroundContext { backgroundContext in
        let entity = NSEntityDescription.entityForName("User", inManagedObjectContext: backgroundContext)!
        let object = NSManagedObject(entity: entity, insertIntoManagedObjectContext: backgroundContext)
        object.setValue("Background", forKey: "name")
        object.setValue("Background@gmail.com", forKey: "email")
        try! backgroundContext.save()
    }
}

以上基本上是 DATAStack 给我们带来的便利性,可以很方便的维护一个拥有两个上下文的Stack。当然还有一些其他的功能,你可以具体看看文档。

QueryKit

当我们拥有了 DATAStack 之后,你会发现我们在获取数据的时候还是会写很多重复的代码,而且不够优雅。好在QueryKit 帮我们处理好了这一切,起码我认为还是不错的处理方式。

同样呢,首先不会去分析它的源码,我们先来简单的看看是怎么使用的。

首先呢第一步我们需要实例化一个 QuerySet 对象

let querySort = QuerySet<User>(context, User.entityName) ,这是实例化一个最简单的 QuerySet 。 你可以在后边进行链式调用,来添加更多的规则

let querySort = QuerySet<User>(context, User.entityName)
                 .filter(NSPredicate(format: "name == '%@'", "Kyle"))
                 .exclude(NSPredicate(format: "eamil == '%@'", "root@dowhile.net"))

也许你发现了,你在写一些 NSPredicate 使用了一些字符串来表示属性。对的这样很容易出错!这个时候呢我们可以通过 QueryKit 给我们提供的 Attribute 类型来扩展我们的User

extension User {
 static var name:Attribute<String> { return Attribute("name") }
 static var email:Attribute<Int> { return Attribute("email") }
}

在扩展了之后,我们来重写上边的代码

let querySort = QuerySet<User>(context, User.entityName)
                .filter { $0.name == "Kyle" }
                .exclude { $0.email == "root@dowhile.net" }

是的,我们可以通过表达式来完成一个NSPredicate , 像是这个样子。

let namePredicate = Person.name == "Kyle"
let agePredicate = Person.age > 25
let ageSortDescriptor = Person.age.descending()

我们还可以给 QuerySet 设置 Ordering

queryset.orderBy { $0.name.ascending() }

queryset.orderBy(Person.name.ascending())

queryset.orderBy(NSSortDescriptor(key: "name", ascending: true))

是不是觉得太棒了。再也不用去复制粘贴属性了。那在这里要强调一点的是

A QuerySet is lazy, creating a QuerySet doesn’t involve querying Core Data. QueryKit won’t actually execute the query until the QuerySet is evaluated.

那好,我们设置好了 QuerySet 如何把这些符合条件的数据获取到呢?

  1. Multiple objects

for person in try! queryset.array() {
 println("Hello \(person.name).")
}
  1. First object

let kyle = try? queryset.first()

  1. Last object

let kyle = try? queryset.last()

  1. Object at index

let katie = try? queryset.object(3)

  1. Count

let numberOfPeople = try? queryset.count()

  1. Deleting

let deleted = try? queryset.delete()

  1. 什么这些还不够你用?那么你可以通过获取 NSFetchRequest 来自己配置更多的选项

let request = querySort.fetchRequest

其实,QueryKit 还有更多的功能,你可以通过阅读 readme 文件来学习。

之后我们会来学习这两个库的源码。


dowhilenet
654 声望10 粉丝