標籤:ios coredata faulting 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 -> SalesGillian -> SalesHector -> Engineering [fault fires]Michelle -> Marketing
明顯,這樣的一次取一個的方式是效率很低的,CoreData提供了兩種解決方案
NSArray *array = [NSArray arrayWithObjects:fault1, fault2, ..., nil];NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self IN %@", array];
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存在記憶體裡,造成對象的不一致。
iOS CoreData詳解(四)Faulting and Uniquing