iOS CoreData详解(四)Faulting and Uniquing

原创blog,转载请注明出处
blog.csdn.net/hello_hwc
欢迎关注我的iOS SDK详解专栏
http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html


前言,faulting 和 uniquing是理解CoreData的两个比较关键的概念,这里详细的讲解一下。
先简单看看二者的概念

  • faulting 是一种CoreData降低内存使用的机制,是惰性加载的一种。
  • Uniquing是辅助faulting的机制,它保证了在一个managed object context中只有一个managed object来表达一条记录

faulting 限制对象图的大小

一个fault在内存里就是一个对象的占位符,这个占位符代表的对象并没有完全取到内存里。分为两种:

  1. 一个managed object的fault就是相关类的对象,但是对象的持久化存储的属性没有被初始化
  2. 一个relationship 的fault表示对应的集合的实例。

这样的占位符的方式降低了内存使用,也不需要把fault对象相关的对象再取到内存里。
例如,取出如图的一个employee,那么员工的manager,department,reports默认都是fault来表示的
技术分享
fault对于使用者来说是透明的,在用户使用到对应的fault对象的持久化存储的属性时候,coredata会自动从磁盘取出对应数据,这个过程称为Firing Faults.


Firing Faults的过程

  1. CoreData先到持久化存储协调器的Cache里查找,如果有则返回,这个过程是否效率很高
  2. 如果没有,则自动执行一次fetch,把对应的数据返回,并且加入到持久化存储协调器的Cache里

以下对managedObject的调用不会导致firing faults

isEqual:, 
hash, 
class, 
self, 
zone, 
isProxy, 
isKindOfClass:,
isMemberOfClass:, 
conformsToProtocol:,
respondsToSelector:, 
description,
managedObjectContext, 
entity, 
objectID, 
isInserted, 
isUpdated, 
isDeleted, 
isFault.

关于Faulting的性能优化

毫无疑问,一次fire一个fault的效率是很低的。举个例子
还是员工和部门的对象图
技术分享
取出一些员工,并且打印对应的Department name

NSFetchRequest * employeesFetch = <#A fetch request for Employees#>
// The request should include a predicate -- if you don‘t have a predicate here,
// you should probably just fetch all the Departments.
NSArray *fetchedEmployees = [moc executeFetchRequest:employeesFetch error:&error];
for (Employee *employee in fetchedEmployees)
{
    NSLog(@"%@ -> %@ department", employee.name, employee.department.name);
}

这样会导致firing faults如下

Jack -> Sales [fault fires]
Jill -> Marketing [fault fires]
Benjy -> Sales
Gillian -> Sales
Hector -> Engineering [fault fires]
Michelle -> Marketing

明显,这样的一次取一个的方式是效率很低的,CoreData提供了两种解决方案

  • Batch faulting 一次处理一批
NSArray *array = [NSArray arrayWithObjects:fault1, fault2, ..., nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self IN %@", array];
  • Pre-fetching 预提取
NSManagedObjectContext *context = /* get the context */;
NSEntityDescription *employeeEntity = [NSEntityDescription
    entityForName:@"Employee" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:employeeEntity];
[request setRelationshipKeyPathsForPrefetching:
    [NSArray arrayWithObject:@"department"]]

把已经初始化的对象转换为fault

把已经初始化的对象转为fault有很多好处

  • 降低内存使用
  • 保证对象的数据都是最新的。(多线程情况下)

把一个对象转为fault使用这个方法refreshObject:mergeChanges:,会把对应的持久化存储属性设为nil,断开相关对象的强引用。


Uniquing

上文提到了:Uniquing是辅助faulting的机制,它保证了在一个managed object context中只有一个managed object来表达一条记录.
例如:取出两个Employee,对应都有代表fault的Department
技术分享
在之后进行了firing faulting后,Department被取出,如果这两个是同一个Department,那么会自动指向一个对象。
技术分享

如果,没有这个机制,那么会造成多个相同的Department存在内存里,造成对象的不一致。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。