版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.09.14 |
前言
KVO
具有更强大的功能,是苹果给我们的一个回调机制,在某个对象注册监听者后,在被监听的对象发生改变时,对象会发送一个通知给监听者,以便监听者执行回调操作。接下来几篇就详细的解析一下KVO。感兴趣的可以看上面几篇。
1. KVO解析(一) —— 基本了解
2. KVO解析(二) —— 一个简单的KVO实现
3. KVO解析(三) —— KVO合规性
Faulting and Uniquing
故障通过在持久存储中保留占位符对象(故障)来减少应用程序的内存使用。 一个名为uniquing
的相关功能可以确保在给定的托管对象上下文中,您不会有多个托管对象来表示给定的记录。
faulting
和 uniquing
是理解CoreData
的两个比较关键的概念。
-
faulting
是一种CoreData
降低内存使用的机制,是惰性加载的一种。 -
Uniquing
是辅助faulting
的机制,它保证了在一个managed object context
中只有一个managed object
来表达一条记录。
Faulting Limits the Size of the Object Graph - 故障限制对象图的大小
管理对象通常表示持久存储中保存的数据。 在某些情况下,被管理对象可能是一个故障 - 其属性值尚未从外部数据存储加载的对象。 故障可减少应用程序消耗的内存量。 故障是表示尚未完全实现的管理对象的占位符对象或表示关系的集合对象:
- 管理对象故障是适当类的实例,但其持久变量尚未初始化。
- 关系故障是代表关系的集合类的子类。
故障允许Core Data
在对象图上放置边界。 由于没有实现故障,管理对象故障消耗的内存较少,与故障相关的管理对象根本不需要在内存中进行表示。
为了说明,考虑允许用户获取和编辑有关单个员工的详细信息的应用程序。 员工与经理和部门有关系,这些对象又有其他关系。 如果您从永久存储中检索一个Employee
对象,则其经理,部门和报表关系最初由故障表示。 下图显示了以故障为代表的员工部门关系。
虽然这个错误是Department
类的一个实例,但它还没有被实现 - 它的持久实例变量都没有设置。 这意味着,不仅部门对象本身消耗的内存较少,也不需要填充其员工关系。 如果要求对象图完成,则要编辑单个员工的单个属性,最终将需要创建对象以表示整个公司结构。
Firing Faults - 故障开启
故障处理是透明的 - 您不必执行抓取来实现故障。 如果在某个阶段访问了故障对象的持久属性,Core Data
将自动检索对象的数据并初始化对象。 这个过程通常被称为触发故障。 如果您访问Department对象(例如,其名称)上的属性,则会发生故障触发,Core Data将执行撷取以检索所有对象的所有属性。(有关触发故障开启可以参考NSManagedObject)。
当访问故障的持久属性(如firstName)时,Core Data
将自动触发故障。 然而,单独触发故障可能是低效的,并且有更好的策略从永久存储器获取数据(请参阅 Decreasing Fault Overhead)。 要有效地处理故障和关系,请参阅 Fetching Managed Objects和Preventing a Fault from Firing。
当故障触发时,如果数据在缓存中可用,则Core Data不会返回到存储。 使用缓存命中,将故障转换为实现的管理对象非常快 - 它与被管对象的正常实例基本相同。 如果数据在缓存中不可用,则Core Data将自动执行故障对象的提取; 这导致到持久存储器的往返行程以获取数据,并且再次将数据高速缓存在存储器中。
一个对象是否是一个故障,只是指一个给定的被管理对象是否具有所有的持久属性,并且可以使用。 如果需要确定对象是否为故障,请调用其isFault方法而不触发故障(不访问任何关系或属性)。 如果isFault
返回NO
,则数据必须在内存中,因此对象不是故障。 但是,如果isFault
返回YES
,则并不意味着数据不在内存中。 数据可能在内存中,或者可能不是,这取决于影响缓存的许多因素。
虽然标准description方法不会导致故障触发,但如果实现访问对象的持久属性的自定义description
方法,则故障将触发。 你们绝对不鼓励用这种方式重写description
。
无法根据需要加载托管对象的各个属性,并避免实现(检索整个对象的所有属性值)。 对于处理大型属性的模式,请参阅 Binary Large Data Objects (BLOBs)。
Turning Objects into Faults - 对象转换为故障
将实现的对象转换为故障在修剪对象图中以及确保属性值为最新时可能很有用。 将受管对象转换为故障会释放不必要的内存,并将其内存中的属性值设置为nil。 (请参阅Reducing Memory Overhead并确保数据更新。)
您可以使用 refreshObject:mergeChanges:方法将实现的对象转换为故障。 如果您将NO作为mergeChanges
参数传递,则必须确保该对象的关系没有更改。 如果有,然后保存上下文,您将引入持久存储参照完整性问题。
当对象变成故障时,将调用其didTurnIntoFault方法。 您可以实施自定义的didTurnIntoFault
方法来执行各种管理功能。
还需要注意的是:Core Data避免了这个unfaulting
术语,因为它是混乱的。 虚拟内存页错误没有unfaulting
。 页面错误被触发,引起,开启或遇到。 当然,您可以通过各种方式将内存释放回内核(使用函数vm_deallocate
,munmap
或sbrk
)。 Core Data将其描述为“turning an object into a fault
”。
Faults and KVO Notifications - 故障和KVO通知
当Core Data将对象变成故障时,键值观察(KVO)更改通知将发送到对象的属性。 如果您正在观察变成故障的对象的属性,并且随后实现了故障,你接收的更改通知的属性值实际上并没有实际上的改变。
虽然这些值从您的角度来看不会从语义上改变,但是随着对象的实现,内存中的字面字节也在改变。 键值观察机制要求Core Data在根据指针比较的角度改变值时发出通知。 KVO需要这些通知来跟踪关键路径和依赖对象的变化。
Uniquing Ensures a Single Managed Object per Record per Context - Uniquing确定每个上下文记录的单个管理对象
Core Data可确保在给定的托管对象上下文中 - persistent store
中的条目仅与一个管理对象相关联。 该技术被称为uniquing
。 没有uniquing
,你可能会得到一个上下文来维护多个对象来表示给定的记录。
例如,考虑下图所示的情况,两名员工已被提取到一个单一managed object context.
中。 每个人都与一个部门有关系,但该部门目前由一个故障表示。
看来每个员工都有一个单独的部门,如果您为每个员工调用部门 - 将部门故障转换为常规对象,则内存中将有两个单独的部门对象。 但是,如果两个员工都属于同一部门(例如Marketing),则Core Data可确保(在给定的托管对象上下文中)仅创建了一个代表市场部门的对象。 如果两个员工都属于同一个部门,则他们的部门关系因此都会引用相同的故障,如下图所示。
没有uniquing
,如果您获取所有员工,并在每个部门中调用部门,从而触发相应的故障 - 每次都会创建一个新的部门对象。 这将导致一些对象,每个对象代表同一个部门,可能包含不同和冲突的数据。 当保存上下文时,将无法确定正确的数据以提交存储。
更广泛地说,在给定上下文中,引用市场部门对象的所有托管对象都引用了相同的实例,即它们具有市场营销部门数据的单一视图,即使市场部门对象是故障的。
这个讨论集中在单一的管理对象上下文中。 每个受管对象上下文都表示数据的不同视图。 如果相同的员工被提取到第二个上下文中,那么它们和相应的Department对象都由内存中的不同对象表示。 不同上下文中的对象可能具有不同的和冲突的数据。 Core Data架构正是检测和解决这些冲突的很好的角色。
后记
这里很大一部分是关于Core Data的,只有一个小点与KVO相关,但是苹果文档写在一起,我就都发出来了,大家感兴趣的也可以看看Core Data方面的知识。未完,待续~~~