RealmResultsController 0.4.4

RealmResultsController 0.4.4

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布上次发布2016年6月
SPM支持 SPM

Pol Quintana 维护。



Swift 编写的用于 Realm 的 NSFetchedResultsController 实现

快速入门

创建 RealmRequest

RealmRequest<T> 需要三个参数

  • 一个谓词
  • 一个 Realm 数据库
  • 排序描述符

其中 T 是一个 Realm 模型

let realm = // Your realm DB
let predicate = NSPredicate(format: "id != 0")
let sortDescriptors = [SortDescriptor(property: "projectID"), SortDescriptor(property: "name")]
let request = RealmRequest<TaskModel>(predicate: predicate, realm: realm, sortDescriptors: sortDescriptors)

创建 RealmResultsController

RealmResultsController<T, U> 需要 4 个参数

  • 一个 RealmRequest<T>
  • 分区键路径(可选)
  • 一个映射器,例如 func mapper(obj: T) -> U(可选)
  • 一个过滤器,例如 func filter(obj: T) -> Bool(可选)

其中 T 是一个 Realm 模型,U 是您想要从 RRC 收到的对象的类型。由于 RRC 在后台工作,我们无法使用常规的 Realm 对象,因此我们可以创建不属于任何 Realm 的对象的副本,或者将对象映射到另一种类型的“实体”U

每个 RRC 的操作都被排入队列,以避免对 willChangeResultsdidChangeResults 进行的无序调用。每个 RRC 都有自己的队列。

注意: TU 可以是同一类型,那么 RRC 将返回 T 对象的副本,但不包括在任何 Realm 中。

什么 filter 为何物? 您可能会问,如果 RealmRequest 已经有了 NSPredicate 来过滤结果,为什么 RRC 仍然接受过滤函数?嗯,非常简单

  • NSPredicate 只允许你按 Realm 属性过滤,功能非常有限。
  • 有了这个额外的过滤块,您可以有更细粒度的结果,使用关系的值进行过滤,或者根据模型内部方法的结果进行过滤。
  • 这是对 Realm 中 NSPredicate 功能限制的一种解决方案 :)
  • 这并非强制性的,默认情况下,过滤闭包为空。

⚠️- 如果sectionKeyPath不为空,它必须匹配RealmRequest的第一个SortDescriptor。否则将引发异常。

⚠️- Realm不接受访问关系属性中的SortDescriptor,这限制了sectionKeyPath只能是当前对象的属性

// In this example we ask for TaskModel objects in Realm,
// and we want it to map the results to a Task entity,
// this entity defines it's own mapper in `Task.map`
let rrc = RealmResultsController<TaskModel, Task>(request: request, sectionKeyPath: sectionKeypath, mapper: Task.map, filter: MyFilterFunc)
rrc.delegate = self

// With NIL filter, same as before, but we can ignore the 
// filter property if we don't want to use it
let rrc = RealmResultsController<TaskModel, Task>(request: request, sectionKeyPath: sectionKeypath, mapper: Task.map)
rrc.delegate = self

// OR without mapper nor filter, this is a special init. 
// Since we don't want to change the result type, we say to the RRC that `T` is the same as `U`. 
// The filter will be nil.
let rrc = RealmResultsController<TaskModel, TaskModel>(request: request, sectionKeyPath: sectionKeypath)
rrc.delegate = self

实现RealmResultsControllerDelegate方法

RealmResultsControllerDelegate有4个必须包含的方法

func willChangeResults(controller: AnyObject)
func didChangeObject<U>(object: U, controller: AnyObject, oldIndexPath: NSIndexPath, newIndexPath: NSIndexPath, changeType: RealmResultsChangeType)
func didChangeSection<U>(section: RealmSection<U>, controller: AnyObject, index: Int, changeType: RealmResultsChangeType)
func didChangeResults(controller: AnyObject)

您可以使用以下公共方法访问RRC中的元素

// Returns all the Sections including its objects
public var sections: [RealmSection<U>] 

// count of Sections
public var numberOfSections: Int 

// Number of Objects in a Section
public func numberOfObjectsAt(sectionIndex: Int) -> Int 

//Object at a given indexPath (ideal for cellForRow... in table views )
public func objectAt(indexPath: NSIndexPath) -> U 

// Change the filter currently used. IMPORTANT! after calling 
// this method you should reload your table `tableView.realoadData()`
public func updateFilter(newFilter: T -> Bool) 
RealmResultsChangeType

这是一个包含四种不同类型的枚举

  • 插入
  • 删除
  • 更新
  • 移动
enum RealmResultsChangeType: String {
    case Insert
    case Delete
    case Update
    case Move
}

初始获取

为了开始接收RealmResultsController事件,您需要进行初始获取。之后,您将在代理方法中开始接收更改

rrc.performFetch()

重要信息

添加/删除对象的方法

为了使RealmResultsController在Realm中收到更改事件,您必须使用我们的自定义方法。这些在Realm Extension中声明,并且是原始Realm方法的包装器

添加
public func addNotified<N: Object>(object: N, update: Bool = false)
public func addNotified<S: SequenceType where S.Generator.Element: Object>(objects: S, update: Bool = false)
public func createNotified<T: Object>(type: T.Type, value: AnyObject = [:], var update: Bool = false) -> T?
删除
public func deleteNotified(object: Object)
public func deleteNotified<S: SequenceType where S.Generator.Element: Object>(objects: S)

通知单个对象更新

RRC无法检测写入事务内部的单个对象更新。通知对象更改(非添加或创建)是通过调用notifyChange()的方法通知的。

notifyChange()是 RealmObject 扩展中的一个方法,以下是其使用示例

    let user = User()
    user.name = "old name"

    realm.write {
        realm.addNotified(user)
    }

    // STUFF GOING ON...

    realm.write {
        user.name = "new name"
        user.notifyChange() //Notifies that there's a change on the object
    }

RealmRequest

您可以使用RealmRequest检索请求的对象,而无需将其与RealmResultsController关联。它将返回Results<T>

let predicate = NSPredicate(format: "id != 0")
let sortDescriptors = [SortDescriptor(property: "projectID"), SortDescriptor(property: "name")]
let sectionKeypath = "projectID"
let request = RealmRequest<TaskModel>(predicate: predicate, realm: realm, sortDescriptors: sortDescriptors)

//Execute the request
let objects = request.execute()

您还可以让Realm执行某些请求

let objects = realm.execute(request)

在Realm扩展上添加的其他方法

ToArray()

在Realm中,当您请求DB中的对象时,您将收到Results<T>。因此,我们添加了toArray()方法来将其转换为常用的Array<T>

let objects = realm.objects(TaskModel.self).toArray()

监听Realm更改

如果您正在使用RRC方法添加/删除对象,您将能够监听所有Realm更改。

只需将观察者添加到对象,如下所示

let object = Object()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "YOUR_FUNC", name: object.objectIdentifier(), object: nil)

objectIdentifier()是定义在 Object 扩展中的一个方法,将针对给定对象构建一个标识符。其结构为ObjectiveType-PrimaryKeyValue

免责声明

目前,RRC无法检测通过另一个对象的关联保存的对象引入的更改。

示例

let user = User()
user.id = 123
user.name = "John"
realm.addNotified(user)

let task = Task()
user.name = "Steven" //This change is not going to be notified
task.assignedUser = user
realm.addNotified(task)

// There will be only one notification for the Task object

示例

要使用示例,只需运行以下命令使用 Carthage 安装 Realm 依赖

carthage update --platform iOS

安装

手动安装

复制 RealmResultsController 源文件

/Source 文件夹内的文件复制到您的项目中

安装 Swift 2.0 的 Realm

更多信息请参见这里

技术细节

  • Swift 2.2

许可证

所有源代码均在 MIT 许可证 下授权。

如果您使用了它,我们很高兴得知这一点。