mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-27 00:01:00 +08:00
Added new logging component for Core Data cacheing subsystem. Fixed performance degradation in entity cache. Enabled RKManagedObjectCacheing callbacks to accelerate mapping, disabled processPendingChanges
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
|
||||
// Set Logging Component
|
||||
#undef RKLogComponent
|
||||
#define RKLogComponent lcl_cRestKitCoreData
|
||||
#define RKLogComponent lcl_cRestKitCoreDataCache
|
||||
|
||||
@interface RKEntityByAttributeCache ()
|
||||
@property (nonatomic, retain) NSMutableDictionary *attributeValuesToObjectIDs;
|
||||
@@ -68,6 +68,7 @@
|
||||
[_attribute release];
|
||||
[_managedObjectContext release];
|
||||
[_attributeValuesToObjectIDs release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -83,6 +84,8 @@
|
||||
|
||||
- (BOOL)shouldCoerceAttributeToString:(NSString *)attributeValue
|
||||
{
|
||||
return NO;
|
||||
|
||||
if ([attributeValue isKindOfClass:[NSString class]] || [attributeValue isEqual:[NSNull null]]) {
|
||||
return NO;
|
||||
}
|
||||
@@ -93,6 +96,7 @@
|
||||
|
||||
- (void)load
|
||||
{
|
||||
RKLogInfo(@"Loading entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute);
|
||||
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
|
||||
[fetchRequest setEntity:self.entity];
|
||||
[fetchRequest setResultType:NSManagedObjectIDResultType];
|
||||
@@ -106,7 +110,7 @@
|
||||
[fetchRequest release];
|
||||
|
||||
self.attributeValuesToObjectIDs = [NSMutableDictionary dictionaryWithCapacity:[objectIDs count]];
|
||||
for (NSManagedObjectID* objectID in objectIDs) {
|
||||
for (NSManagedObjectID *objectID in objectIDs) {
|
||||
NSError *error = nil;
|
||||
NSManagedObject *object = [self.managedObjectContext existingObjectWithID:objectID error:&error];
|
||||
if (! object && error) {
|
||||
@@ -119,6 +123,7 @@
|
||||
|
||||
- (void)flush
|
||||
{
|
||||
RKLogInfo(@"Flushing entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute);
|
||||
self.attributeValuesToObjectIDs = nil;
|
||||
}
|
||||
|
||||
@@ -158,7 +163,7 @@
|
||||
- (NSSet *)objectsWithAttributeValue:(id)attributeValue
|
||||
{
|
||||
attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue;
|
||||
NSMutableSet *set = [self.attributeValuesToObjectIDs valueForKey:attributeValue];
|
||||
NSMutableSet *set = [self.attributeValuesToObjectIDs objectForKey:attributeValue];
|
||||
if (set) {
|
||||
NSSet *objectIDs = [NSSet setWithSet:set];
|
||||
NSMutableSet *objects = [NSMutableSet setWithCapacity:[objectIDs count]];
|
||||
@@ -181,8 +186,7 @@
|
||||
attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue;
|
||||
if (attributeValue) {
|
||||
NSManagedObjectID *objectID = [object objectID];
|
||||
BOOL isTemporary = [objectID isTemporaryID];
|
||||
NSMutableSet *set = [self.attributeValuesToObjectIDs valueForKey:attributeValue];
|
||||
NSMutableSet *set = [self.attributeValuesToObjectIDs objectForKey:attributeValue];
|
||||
if (set) {
|
||||
[set addObject:objectID];
|
||||
} else {
|
||||
@@ -204,7 +208,7 @@
|
||||
attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue;
|
||||
if (attributeValue) {
|
||||
NSManagedObjectID *objectID = [object objectID];
|
||||
NSMutableSet *set = [self.attributeValuesToObjectIDs valueForKey:attributeValue];
|
||||
NSMutableSet *set = [self.attributeValuesToObjectIDs objectForKey:attributeValue];
|
||||
if (set) {
|
||||
[set removeObject:objectID];
|
||||
}
|
||||
|
||||
@@ -39,10 +39,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
static NSPredicate *predicate = nil;
|
||||
// if (! predicate) {
|
||||
predicate = [NSComparisonPredicate
|
||||
predicateWithLeftExpression:[NSExpression expressionForKeyPath:primaryKeyAttribute]
|
||||
rightExpression:[NSExpression expressionForConstantValue:searchValue]
|
||||
modifier:NSDirectPredicateModifier
|
||||
type:NSEqualToPredicateOperatorType
|
||||
options:0];
|
||||
// }
|
||||
// [NSComparisonPredicate
|
||||
// predicateWithLeftExpression:
|
||||
// [NSExpression expressionForEvaluatedObject]
|
||||
// rightExpression:
|
||||
// [NSExpression expressionForConstantValue:objectForID]
|
||||
// modifier:NSDirectPredicateModifier
|
||||
// type:NSEqualToPredicateOperatorType
|
||||
// options:0];
|
||||
// [request setPredicate:predicate];
|
||||
|
||||
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
|
||||
[fetchRequest setEntity:entity];
|
||||
[fetchRequest setFetchLimit:1];
|
||||
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", primaryKeyAttribute, searchValue]];
|
||||
[fetchRequest setPredicate:predicate];
|
||||
// [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", primaryKeyAttribute, searchValue]];
|
||||
NSArray *objects = [NSManagedObject executeFetchRequest:fetchRequest inContext:managedObjectContext];
|
||||
RKLogDebug(@"Found objects '%@' using fetchRequest '%@'", objects, fetchRequest);
|
||||
[fetchRequest release];
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "RKInMemoryManagedObjectCache.h"
|
||||
#import "NSEntityDescription+RKAdditions.h"
|
||||
#import "RKEntityCache.h"
|
||||
#import "RKLog.h"
|
||||
|
||||
@@ -18,13 +19,9 @@ static NSString * const RKInMemoryObjectManagedObjectCacheThreadDictionaryKey =
|
||||
|
||||
@implementation RKInMemoryManagedObjectCache
|
||||
|
||||
- (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity
|
||||
withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute
|
||||
value:(id)primaryKeyValue
|
||||
inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext {
|
||||
- (RKEntityCache *)cacheForEntity:(NSEntityDescription *)entity inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
|
||||
{
|
||||
NSAssert(entity, @"Cannot find existing managed object without a target class");
|
||||
NSAssert(primaryKeyAttribute, @"Cannot find existing managed object instance without mapping");
|
||||
NSAssert(primaryKeyValue, @"Cannot find existing managed object by primary key without a value");
|
||||
NSAssert(managedObjectContext, @"Cannot find existing managed object with a context");
|
||||
NSMutableDictionary *contextDictionary = [[[NSThread currentThread] threadDictionary] objectForKey:RKInMemoryObjectManagedObjectCacheThreadDictionaryKey];
|
||||
if (! contextDictionary) {
|
||||
@@ -40,14 +37,42 @@ static NSString * const RKInMemoryObjectManagedObjectCacheThreadDictionaryKey =
|
||||
[entityCache release];
|
||||
}
|
||||
|
||||
if (! [entityCache isEntity:entity cachedByAttribute:primaryKeyAttribute]) {
|
||||
RKLogInfo(@"Cacheing instances of Entity '%@' by attribute '%@'", entity.name, primaryKeyAttribute);
|
||||
[entityCache cacheObjectsForEntity:entity byAttribute:primaryKeyAttribute];
|
||||
RKEntityByAttributeCache *attributeCache = [entityCache attributeCacheForEntity:entity attribute:primaryKeyAttribute];
|
||||
if (! [entityCache isEntity:entity cachedByAttribute:entity.primaryKeyAttribute]) {
|
||||
RKLogInfo(@"Cacheing instances of Entity '%@' by primary key attribute '%@'", entity.name, entity.primaryKeyAttribute);
|
||||
[entityCache cacheObjectsForEntity:entity byAttribute:entity.primaryKeyAttribute];
|
||||
RKEntityByAttributeCache *attributeCache = [entityCache attributeCacheForEntity:entity attribute:entity.primaryKeyAttribute];
|
||||
RKLogTrace(@"Cached %d objects", [attributeCache count]);
|
||||
}
|
||||
|
||||
return entityCache;
|
||||
}
|
||||
|
||||
// TODO: This method signature needs to be cleaned up... Remove the primaryKeyAttribute being passed around.
|
||||
- (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity
|
||||
withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute
|
||||
value:(id)primaryKeyValue
|
||||
inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
|
||||
{
|
||||
RKEntityCache *entityCache = [self cacheForEntity:entity inManagedObjectContext:managedObjectContext];
|
||||
return [entityCache objectForEntity:entity withAttribute:primaryKeyAttribute value:primaryKeyValue];
|
||||
}
|
||||
|
||||
- (void)didFetchObject:(NSManagedObject *)object
|
||||
{
|
||||
RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext];
|
||||
[entityCache addObject:object];
|
||||
}
|
||||
|
||||
- (void)didCreateObject:(NSManagedObject *)object
|
||||
{
|
||||
RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext];
|
||||
[entityCache addObject:object];
|
||||
}
|
||||
|
||||
- (void)didDeleteObject:(NSManagedObject *)object
|
||||
{
|
||||
RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext];
|
||||
[entityCache removeObject:object];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -170,11 +170,20 @@
|
||||
if (primaryKeyAttribute && primaryKeyValue && NO == [primaryKeyValue isEqual:[NSNull null]]) {
|
||||
object = [self.objectStore.cacheStrategy findInstanceOfEntity:entity
|
||||
withPrimaryKeyAttribute:self.primaryKeyAttribute value:primaryKeyValue inManagedObjectContext:[self.objectStore managedObjectContextForCurrentThread]];
|
||||
|
||||
if (object && [self.objectStore.cacheStrategy respondsToSelector:@selector(didFetchObject:)]) {
|
||||
[self.objectStore.cacheStrategy didFetchObject:object];
|
||||
}
|
||||
}
|
||||
|
||||
if (object == nil) {
|
||||
object = [[[NSManagedObject alloc] initWithEntity:entity
|
||||
insertIntoManagedObjectContext:[_objectStore managedObjectContextForCurrentThread]] autorelease];
|
||||
[object setValue:primaryKeyValue forKey:primaryKeyAttribute];
|
||||
|
||||
if ([self.objectStore.cacheStrategy respondsToSelector:@selector(didCreateObject:)]) {
|
||||
[self.objectStore.cacheStrategy didCreateObject:object];
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
manually invoke processPendingChanges to prevent recreating objects with the same primary key.
|
||||
See https://github.com/RestKit/RestKit/issues/661
|
||||
*/
|
||||
[[[(RKManagedObjectMapping *)self.objectMapping objectStore] managedObjectContextForCurrentThread] processPendingChanges];
|
||||
// [[[(RKManagedObjectMapping *)self.objectMapping objectStore] managedObjectContextForCurrentThread] processPendingChanges];
|
||||
[self connectRelationships];
|
||||
}
|
||||
return success;
|
||||
|
||||
@@ -56,6 +56,7 @@ _lcl_component(RestKitNetworkQueue, "restkit.network.queue",
|
||||
_lcl_component(RestKitNetworkReachability, "restkit.network.reachability", "RestKit/Network/Reachability")
|
||||
_lcl_component(RestKitObjectMapping, "restkit.object_mapping", "RestKit/ObjectMapping")
|
||||
_lcl_component(RestKitCoreData, "restkit.core_data", "RestKit/CoreData")
|
||||
_lcl_component(RestKitCoreDataCache, "restkit.core_data.cache", "RestKit/CoreData/Cache")
|
||||
_lcl_component(RestKitCoreDataSearchEngine, "restkit.core_data.search_engine", "RestKit/CoreData/SearchEngine")
|
||||
_lcl_component(RestKitSupport, "restkit.support", "RestKit/Support")
|
||||
_lcl_component(RestKitSupportParsers, "restkit.support.parsers", "RestKit/Support/Parsers")
|
||||
|
||||
@@ -456,6 +456,7 @@
|
||||
}
|
||||
|
||||
- (void)testMappingAPayloadContainingRepeatedObjectsPerformsAcceptablyWithInMemoryMappingCache {
|
||||
RKLogConfigureByName("RestKit/CoreData/Cache", RKLogLevelTrace);
|
||||
RKManagedObjectStore *store = [RKTestFactory managedObjectStore];
|
||||
store.cacheStrategy = [RKInMemoryManagedObjectCache new];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user