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在内存里就是一个对象的占位符,这个占位符代表的对象并没有完全取到内存里。分为两种:
- 一个managed object的fault就是相关类的对象,但是对象的持久化存储的属性没有被初始化
- 一个relationship 的fault表示对应的集合的实例。
这样的占位符的方式降低了内存使用,也不需要把fault对象相关的对象再取到内存里。
例如,取出如图的一个employee,那么员工的manager,department,reports默认都是fault来表示的
fault对于使用者来说是透明的,在用户使用到对应的fault对象的持久化存储的属性时候,coredata会自动从磁盘取出对应数据,这个过程称为Firing Faults.
Firing Faults的过程
- CoreData先到持久化存储协调器的Cache里查找,如果有则返回,这个过程是否效率很高
- 如果没有,则自动执行一次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存在内存里,造成对象的不一致。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。