SugarRecord For CoreData

What is SugarRecord?

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 去初始化一个 storageSugarRecord提供了两种默认的方法,一个是创建一个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 来提供给Storagefetch使用

    // 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:

更多的细节你可以去看这个文档。

SugarRecord 文档

这里给上我自己在使用时做的一个小例子Github地址

同时我还做了一个对Realm操作的demoGithub地址


dowhilenet
654 声望10 粉丝