SugarRecord For CoreData
SugarRecord is a persistence wrapper designed to make working with persistence solutions like CoreData/Realm/… in a much easier way. Thanks to SugarRecord you’ll be able to use CoreData with just a few lines of code: Just choose your stack and start playing with your data.
SugarRecord
给我们简化了使用CoreData的步骤(同时他也可以用来操作Realm),可以让我们用更少的代码来使用CoreData,而且还提供了对iCloud
的存储。
而且它支持各种编程范式, 你可以选择你所需要的
pod "SugarRecord/CoreData"
pod "SugarRecord/CoreData+iCloud"
pod "SugarRecord/CoreData+RX"
pod "SugarRecord/CoreData+RX+iCloud"
pod "SugarRecord/CoreData+RAC"
pod "SugarRecord/CoreData+RAC+iCloud"
pod "SugarRecord/Ream"
pod "SugarRecord/Realm+RX"
pod "SugarRecord/Realm+RAC"
Contexts
如果你使用过CoreData
的话会发现维护多个NSManagedObjectContext
是一个挺麻烦的事情。SugarRecord
给我们提供了三种Context
• MainContext: Use it for main thread operations, for example fetches whose data will be presented in the UI.
这个用在主线成中的操作,例如我们获取到数据在UI上边显示
• SaveContext: Use this context for background operations. The context is initialized when the storage instance is created. That context is used for storage operations.
这个用在后台线程中的操作
• MemoryContext: Use this context when you want to do some tests and you don't want your changes to be persisted.
Creating your Storage
A storage represents your database, Realm, or CoreData. The first step to start
using SugarRecord is initializing the storage. SugarRecord provides two default
storages, one for CoreData, CoreDataDefaultStorage and another one for Realm,
RealmDefaultStorage.
一个 storage 就代表着你的一个 database、realm 或者是 CoreData,首先第一步呢就是去使用SugarRecord
去初始化一个 storage
,SugarRecord
提供了两种默认的方法,一个是创建一个CoreDataDefaultStorage
另一个是用来创建 RealmDefaultStorage
// Initializing CoreDataDefaultStorage
func coreDataStorage() -> CoreDataDefaultStorage {
let store = CoreData.Store.Named("db")
let bundle = NSBundle(forClass: self.classForCoder())
let model = CoreData.ObjectModel.Merged([bundle])
let defaultStorage = try! CoreDataDefaultStorage(store: store, model: model)
return defaultStorage
}
Fetching data
let pedros: [Person] = try! db.fetch(Request<Person>().filteredWith("name", equalTo: "Pedro"))
let tasks: [Task] = try! db.fetch(Request<Task>())
let citiesByName: [City] = try! db.fetch(Request<City>().sortedWith("name", ascending: true))
let predicate: NSPredicate = NSPredicate(format: "id == %@", "AAAA")
let john: User? = try! db.fetch(Request<User>().filteredWith(predicate: predicate)).first
在这里呢我们的筛选条件可以使用NSPredicate
这意味着,如果你是从CoreData
转过来的话是很方便的。
当你执行db.fetch
的时候SugarRecord
就使用的是mainContext
,你可以去查看fetch
的对应实现
public class CoreDataDefaultStorage: Storage {
.....
}
// CoreDataDefaultStorage 继承了 Storage这个协议
//Storage 协议对 fetch 有了默认的实现
//我们可以看到在默认的实现中 使用的是 mainContext
public extension Storage {
func fetch<T: Entity>(request: Request<T>) throws -> [T] {
return try self.mainContext.fetch(request)
}
}
Request
Request
是一个结构体,他用来构成起获取数据时的约束。我们可以使用它的工厂方法来生成一个Request
来提供给Storage
的fetch
使用
// MARK: - Public Builder Methods
public func filteredWith(predicate predicate: NSPredicate) -> Request<T> {
return self
.request(withPredicate: predicate)
}
public func filteredWith(key: String, equalTo value: String) -> Request<T> {
return self
.request(withPredicate: NSPredicate(format: "\(key) == %@", value))
}
public func sortedWith(sortDescriptor sortDescriptor: NSSortDescriptor) -> Request<T> {
return self
.request(withSortDescriptor: sortDescriptor)
}
public func sortedWith(key: String?, ascending: Bool, comparator cmptr: NSComparator) -> Request<T> {
return self
.request(withSortDescriptor: NSSortDescriptor(key: key, ascending: ascending, comparator: cmptr))
}
public func sortedWith(key: String?, ascending: Bool) -> Request<T> {
return self
.request(withSortDescriptor: NSSortDescriptor(key: key, ascending: ascending))
}
public func sortedWith(key: String?, ascending: Bool, selector: Selector) -> Request<T> {
return self
.request(withSortDescriptor: NSSortDescriptor(key: key, ascending: ascending, selector: selector))
}
Remove/Insert/Update operations
我们对数据库的最常用的操作无非就是增删查改了。
Although Contexts offer insertion and deletion methods that you can use it directly SugarRecords aims at using the operation method method provided by the storage for operations that imply modifications of the database models:
Contexts
给我们提供了插入和删除的操作,你可以直接的使用它。SugarRecords
又致力于使用operation
这个方法来 对storage
操作。
• Context: You can use it for fetching, inserting, deleting. Whatever you need to do with your data.
通过 context 你可以进行增删查改的操作
• Save: All the changes you apply to that context are in a memory state unless you call the save() method. That method will persist the changes to your store and propagate them across all the available contexts.
你所有对context的改变都是在内存中的,直到你使用了 save() 这个方法之后才会吧它持久化。
do {
db.operation { (context, save) throws -> Void in
// Do your operations here
save()
}
}
catch {
// There was an error in the operation
}
当我们在执行上边的方法的时候默认使用的就是saveContext
,
public func operation(operation: (context: Context, save: () -> Void) throws -> Void) throws {
let context: NSManagedObjectContext = self.saveContext as! NSManagedObjectContext
var _error: ErrorType!
context.performBlockAndWait {
do {
try operation(context: context, save: { () -> Void in
do {
try context.save()
}
catch {
_error = error
}
if self.rootSavingContext.hasChanges {
self.rootSavingContext.performBlockAndWait({
do {
try self.rootSavingContext.save()
}
catch {
_error = error
}
})
}
})
} catch {
_error = error
}
}
if let error = _error {
throw error
}
}
Insert/Update
在SugarRecord
的事例中给了两种不同的例子
You can use the context new() method to initialize a model without inserting it in the context:
In order to insert the model into the context you use the insert() method.
do {
db.operation { (context, save) throws -> Void in
let newTask: Track = try! context.new()
newTask.name = "Make CoreData easier!"
try! context.insert(newTask)
save()
}
}
catch {
// There was an error in the operation
}
You can use the create() for initializing and inserting in the context in the same operation:
do {
db.operation { (context, save) throws -> Void in
let newTask: Track = try! context.create()
newTask.name = "Make CoreData easier!"
save()
}
}
catch {
// There was an error in the operation
}
从字面上的理解来看的话,使用new()
方法的话你需要调用 context.insert()
这个方法去把你的Entity
插入到 cotext
。
而 create
的话,已经存在了context
,去看create
的实现的时候会发现,它调用了new()
和insert()
public func create<T: Entity>() throws -> T {
let instance: T = try self.new()
try self.insert(instance)
return instance
}
可是我测试了new()
不去执行 context.insert()
方法,也能通过save()
去把它持久化了。所以不太理解这里的区别,现在这里挖个坑。如果谁知道的话告诉我,可能是我这里理解的不太对。
Delete a model
In a similar way you can use the remove() method from the context passing the objects you want to remove from the database:
更多的细节你可以去看这个文档。
这里给上我自己在使用时做的一个小例子Github地址
同时我还做了一个对Realm操作的demoGithub地址