Permalink
Browse files

Merge branch 'feature/635-accelerate-entity-cache' into development

  • Loading branch information...
blakewatters committed May 15, 2012
2 parents 7656a96 + 9bf89eb commit 2c704e6fdcdcf05c49612a515c9bf083837557b5
Showing with 4,112 additions and 732 deletions.
  1. +31 −1 Code/CoreData/NSEntityDescription+RKAdditions.h
  2. +34 −2 Code/CoreData/NSEntityDescription+RKAdditions.m
  3. +180 −0 Code/CoreData/RKEntityByAttributeCache.h
  4. +279 −0 Code/CoreData/RKEntityByAttributeCache.m
  5. +133 −0 Code/CoreData/RKEntityCache.h
  6. +141 −0 Code/CoreData/RKEntityCache.m
  7. +12 −4 Code/CoreData/RKFetchRequestManagedObjectCache.m
  8. +0 −83 Code/CoreData/RKInMemoryEntityCache.h
  9. +0 −291 Code/CoreData/RKInMemoryEntityCache.m
  10. +0 −1 Code/CoreData/RKInMemoryManagedObjectCache.h
  11. +47 −13 Code/CoreData/RKInMemoryManagedObjectCache.m
  12. +25 −0 Code/CoreData/RKManagedObjectCaching.h
  13. +18 −3 Code/CoreData/RKManagedObjectMapping.m
  14. +1 −1 Code/CoreData/RKManagedObjectMappingOperation.m
  15. +2 −3 Code/CoreData/RKManagedObjectStore.m
  16. +121 −0 Code/Support/RKBenchmark.h
  17. +119 −0 Code/Support/RKBenchmark.m
  18. +1 −0 Code/Support/Support.h
  19. +1 −0 Code/Support/lcl_config_components.h
  20. +3 −2 Gemfile
  21. +8 −4 Gemfile.lock
  22. +22 −0 Rakefile
  23. +60 −18 RestKit.xcodeproj/project.pbxproj
  24. +2,062 −0 Tests/Fixtures/JSON/benchmark_parents_and_children.json
  25. +40 −0 Tests/Fixtures/JSON/parents_and_children.json
  26. +18 −0 Tests/Logic/CoreData/NSEntityDescription+RKAdditionsTest.m
  27. +378 −0 Tests/Logic/CoreData/RKEntityByAttributeCacheTest.m
  28. +175 −0 Tests/Logic/CoreData/RKEntityCacheTest.m
  29. +3 −3 Tests/Logic/CoreData/RKFetchRequestMappingCacheTest.m
  30. +0 −296 Tests/Logic/CoreData/RKInMemoryEntityCacheTest.m
  31. +129 −1 Tests/Logic/CoreData/RKManagedObjectMappingOperationTest.m
  32. +69 −6 Tests/Logic/CoreData/RKManagedObjectMappingTest.m
  33. BIN Tests/Models/Data Model.xcdatamodel/elements
  34. BIN Tests/Models/Data Model.xcdatamodel/layout
@@ -16,6 +16,14 @@
*/
extern NSString * const RKEntityDescriptionPrimaryKeyAttributeUserInfoKey;
+/**
+ The substitution variable used in predicateForPrimaryKeyAttribute.
+
+ **Value**: @"PRIMARY_KEY_VALUE"
+ @see predicateForPrimaryKeyAttribute
+ */
+extern NSString * const RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubstitutionVariable;
+
/**
Provides extensions to NSEntityDescription for various common tasks.
*/
@@ -34,6 +42,28 @@ extern NSString * const RKEntityDescriptionPrimaryKeyAttributeUserInfoKey;
Programmatically configured values take precedence over the user info
dictionary.
*/
-@property(nonatomic, retain) NSString *primaryKeyAttribute;
+@property (nonatomic, retain) NSString *primaryKeyAttribute;
+
+/**
+ Returns a cached predicate specifying that the primary key attribute is equal to the $PRIMARY_KEY_VALUE
+ substitution variable.
+
+ This predicate is cached to avoid parsing overhead during object mapping operations
+ and must be evaluated using [NSPredicate predicateWithSubstitutionVariables:]
+
+ @return A cached predicate specifying the value of the primary key attribute is equal to the $PRIMARY_KEY_VALUE
+ substitution variable.
+ */
+- (NSPredicate *)predicateForPrimaryKeyAttribute;
+
+/**
+ Returns a predicate specifying that the value of the primary key attribute is equal to a given
+ value. This predicate is constructed by evaluating the cached predicate returned by the
+ predicateForPrimaryKeyAttribute with a dictionary of substitution variables specifying that
+ $PRIMARY_KEY_VALUE is equal to the given value.
+
+ @return A predicate speciying that the value of the primary key attribute is equal to a given value.
+ */
+- (NSPredicate *)predicateForPrimaryKeyAttributeWithValue:(id)value;
@end
@@ -10,10 +10,23 @@
#import "NSEntityDescription+RKAdditions.h"
NSString * const RKEntityDescriptionPrimaryKeyAttributeUserInfoKey = @"primaryKeyAttribute";
-static char primaryKeyAttributeKey;
+NSString * const RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubstitutionVariable = @"PRIMARY_KEY_VALUE";
+
+static char primaryKeyAttributeKey, primaryKeyPredicateKey;
@implementation NSEntityDescription (RKAdditions)
+- (void)setPredicateForPrimaryKeyAttribute:(NSString *)primaryKeyAttribute
+{
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == $PRIMARY_KEY_VALUE", primaryKeyAttribute];
+ objc_setAssociatedObject(self,
+ &primaryKeyPredicateKey,
+ predicate,
+ OBJC_ASSOCIATION_RETAIN);
+}
+
+#pragma mark - Public
+
- (NSString *)primaryKeyAttribute
{
// Check for an associative object reference
@@ -22,6 +35,11 @@ - (NSString *)primaryKeyAttribute
// Fall back to the userInfo dictionary
if (! primaryKeyAttribute) {
primaryKeyAttribute = [self.userInfo valueForKey:RKEntityDescriptionPrimaryKeyAttributeUserInfoKey];
+
+ // If we have loaded from the user info, ensure we have a predicate
+ if (! [self predicateForPrimaryKeyAttribute]) {
+ [self setPredicateForPrimaryKeyAttribute:primaryKeyAttribute];
+ }
}
return primaryKeyAttribute;
@@ -32,7 +50,21 @@ - (void)setPrimaryKeyAttribute:(NSString *)primaryKeyAttribute
objc_setAssociatedObject(self,
&primaryKeyAttributeKey,
primaryKeyAttribute,
- OBJC_ASSOCIATION_RETAIN);
+ OBJC_ASSOCIATION_RETAIN);
+ [self setPredicateForPrimaryKeyAttribute:primaryKeyAttribute];
+}
+
+
+- (NSPredicate *)predicateForPrimaryKeyAttribute
+{
+ return (NSPredicate *) objc_getAssociatedObject(self, &primaryKeyPredicateKey);
+}
+
+- (NSPredicate *)predicateForPrimaryKeyAttributeWithValue:(id)value
+{
+ NSDictionary *variables = [NSDictionary dictionaryWithObject:value
+ forKey:RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubstitutionVariable];
+ return [[self predicateForPrimaryKeyAttribute] predicateWithSubstitutionVariables:variables];
}
@end
@@ -0,0 +1,180 @@
+//
+// RKEntityByAttributeCache.h
+// RestKit
+//
+// Created by Blake Watters on 5/1/12.
+// Copyright (c) 2012 RestKit. All rights reserved.
+//
+
+#import <CoreData/CoreData.h>
+
+/**
+ Instances of RKEntityByAttributeCache provide an in-memory caching mechanism
+ for managed objects instances of an entity in a managed object context with
+ the value of one of the object's attributes acting as the cache key. When loaded,
+ the cache will retrieve all instances of an entity from the store and build a
+ dictionary mapping values for the given cache key attribute to the managed object
+ ID for all objects matching the value. The cache can then be used to quickly retrieve
+ objects by attribute value for the cache key without executing another fetch request
+ against the managed object context. This can provide a large performance improvement
+ when a large number of objects are being retrieved using a particular attribute as
+ the key.
+
+ RKEntityByAttributeCache instances are used by the RKEntityCache to provide
+ caching for multiple entities at once.
+
+ @see RKEntityCache
+ */
+@interface RKEntityByAttributeCache : NSObject
+
+///-----------------------------------------------------------------------------
+/// @name Creating a Cache
+///-----------------------------------------------------------------------------
+
+/**
+ Initializes the receiver with a given entity, attribute, and managed object context.
+
+ @param entity The Core Data entity description for the managed objects being cached.
+ @param attributeName The name of an attribute within the cached entity that acts as the cache key.
+ @param managedObjectContext The managed object context the cache retrieves the cached
+ objects from
+ @return The receiver, initialized with the given entity, attribute, and managed object
+ context.
+ */
+- (id)initWithEntity:(NSEntityDescription *)entity attribute:(NSString *)attributeName managedObjectContext:(NSManagedObjectContext *)context;
+
+///-----------------------------------------------------------------------------
+/// @name Getting Cache Identity
+///-----------------------------------------------------------------------------
+
+/**
+ The Core Data entity description for the managed objects being cached.
+ */
+@property (nonatomic, readonly) NSEntityDescription *entity;
+
+/**
+ An attribute that is part of the cached entity that acts as the cache key.
+ */
+@property (nonatomic, readonly) NSString *attribute;
+
+/**
+ The managed object context the receiver fetches cached objects from.
+ */
+@property (nonatomic, readonly) NSManagedObjectContext *managedObjectContext;
+
+/**
+ A Boolean value determining if the receiever monitors the managed object context
+ for changes and updates the cache entries using the notifications emitted.
+ */
+@property (nonatomic, assign) BOOL monitorsContextForChanges;
+
+///-----------------------------------------------------------------------------
+/// @name Loading and Flushing the Cache
+///-----------------------------------------------------------------------------
+
+/**
+ Loads the cache by finding all instances of the configured entity and building
+ an association between the value of the cached attribute's value and the
+ managed object ID for the object.
+ */
+- (void)load;
+
+/**
+ Flushes the cache by releasing all cache attribute value to managed object ID
+ associations.
+ */
+- (void)flush;
+
+///-----------------------------------------------------------------------------
+/// @name Inspecting Cache State
+///-----------------------------------------------------------------------------
+
+/**
+ A Boolean value indicating if the cache has loaded associations between cache
+ attribute values and managed object ID's.
+ */
+- (BOOL)isLoaded;
+
+/**
+ Returns a count of the total number of cached objects.
+ */
+- (NSUInteger)count;
+
+/**
+ Returns the total number of cached objects with a given value for
+ the attribute acting as the cache key.
+
+ @param attributeValue The value for the cache key attribute to retrieve
+ a count of the objects with a matching value.
+ @return The number of objects in the cache with the given value for the cache
+ attribute of the receiver.
+ */
+- (NSUInteger)countWithAttributeValue:(id)attributeValue;
+
+/**
+ Returns the number of unique attribute values contained within the receiver.
+
+ @return The number of unique attribute values within the receiver.
+ */
+- (NSUInteger)countOfAttributeValues;
+
+/**
+ Returns a Boolean value that indicates whether a given object is present
+ in the cache.
+
+ @param object An object.
+ @return YES if object is present in the cache, otherwise NO.
+ */
+- (BOOL)containsObject:(NSManagedObject *)object;
+
+/**
+ Returns a Boolean value that indicates whether one of more objects is present
+ in the cache with a given value of the cache key attribute.
+
+ @param attributeValue The value with which to check the cache for objects with
+ a matching value.
+ @return YES if one or more objects with the given value for the cache key
+ attribute is present in the cache, otherwise NO.
+ */
+- (BOOL)containsObjectWithAttributeValue:(id)attributeValue;
+
+/**
+ Returns the first object with a matching value for the cache key attribute.
+
+ @param attributeValue A value for the cache key attribute.
+ @return An object with the value of attribute matching attributeValue or nil.
+ */
+- (NSManagedObject *)objectWithAttributeValue:(id)attributeValue;
+
+/**
+ Returns the collection of objects with a matching value for the cache key attribute.
+
+ @param attributeValue A value for the cache key attribute.
+ @return An array of objects with the value of attribute matching attributeValue or
+ an empty array.
+ */
+- (NSArray *)objectsWithAttributeValue:(id)attributeValue;
+
+///-----------------------------------------------------------------------------
+/// @name Managing Cached Objects
+///-----------------------------------------------------------------------------
+
+/**
+ Adds a managed object to the cache.
+
+ The object must be an instance of the cached entity.
+
+ @param object The managed object to add to the cache.
+ */
+- (void)addObject:(NSManagedObject *)object;
+
+/**
+ Removes a managed object from the cache.
+
+ The object must be an instance of the cached entity.
+
+ @param object The managed object to remove from the cache.
+ */
+- (void)removeObject:(NSManagedObject *)object;
+
+@end
Oops, something went wrong.

0 comments on commit 2c704e6

Please sign in to comment.