Skip to content

Commit

Permalink
Merge pull request #24 from mutualmobile/cnstoll_performance
Browse files Browse the repository at this point in the history
Major Performance Improvements
  • Loading branch information
cnstoll committed Jul 2, 2013
2 parents ee84fe1 + d49e415 commit 25b7749
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@implementation MMAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[MMJSONPerformanceTestingServer setResultSetSize:100000];
[MMJSONPerformanceTestingServer setResultSetSize:10000];
[ADNRecord registerServerClass:[MMJSONPerformanceTestingServer class]];
//[MMRecord setLoggingLevel:MMRecordLoggingLevelAll];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ - (NSPersistentStoreCoordinator*)persistentStoreCoordinator {
return MM_persistentStoreCoordinator;
}

BOOL memory = NO;
BOOL memory = YES;

if (memory) {
MM_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
Expand Down
14 changes: 8 additions & 6 deletions Source/MMRecord/MMRecordMarshaler.m
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,15 @@ + (NSString *)stringValueForAttribute:(NSAttributeDescription *)attribute value:
}

+ (void)establishRelationshipsOnProtoRecord:(MMRecordProtoRecord *)protoRecord {
for (int i = 0; i < [protoRecord.relationshipProtos count]; ++i) {
MMRecord *fromRecord = protoRecord.record;
MMRecordProtoRecord *relationshipProtoRecord = [protoRecord.relationshipProtos objectAtIndex:i];
MMRecord *toRecord = relationshipProtoRecord.record;
NSRelationshipDescription *relationshipDescription = [protoRecord.relationshipDescriptions objectAtIndex:i];
for (NSRelationshipDescription *relationshipDescription in protoRecord.relationshipDescriptions) {
NSArray *relationshipProtoRecords = [protoRecord relationshipProtoRecordsForRelationshipDescription:relationshipDescription];

[self establishRelationship:relationshipDescription fromRecord:fromRecord toRecord:toRecord];
for (MMRecordProtoRecord *relationshipProtoRecord in relationshipProtoRecords) {
MMRecord *fromRecord = protoRecord.record;
MMRecord *toRecord = relationshipProtoRecord.record;

[self establishRelationship:relationshipDescription fromRecord:fromRecord toRecord:toRecord];
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions Source/MMRecord/MMRecordProtoRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
@property (nonatomic, strong, readonly) MMRecordRepresentation *representation;

// Relationships
// Relationship protos and descriptions are returned in no particular order.
@property (nonatomic, strong, readonly) NSArray *relationshipProtos;
@property (nonatomic, strong, readonly) NSArray *relationshipDescriptions;

Expand All @@ -65,4 +66,7 @@
- (void)addRelationshipProto:(MMRecordProtoRecord *)relationshipProto
forRelationshipDescription:(NSRelationshipDescription *)relationshipDescription;

// Returns the proto records for a given relationship description
- (NSArray *)relationshipProtoRecordsForRelationshipDescription:(NSRelationshipDescription *)relationshipDescription;

@end
54 changes: 47 additions & 7 deletions Source/MMRecord/MMRecordProtoRecord.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@
#import "MMRecordRepresentation.h"

@interface MMRecordProtoRecord ()
@property (nonatomic, strong, readwrite) NSMutableArray *relationshipProtos;
@property (nonatomic, strong, readwrite) NSMutableArray *relationshipDescriptions;
// Dictionary where key = relationship name and value = an NSMutableOrderedSet of proto records
@property (nonatomic, strong, readwrite) NSMutableDictionary *relationshipProtosDictionary;

// Dictionary where key = relationship name and value = relationship description
@property (nonatomic, strong, readwrite) NSMutableDictionary *relationshipDescriptionsDictionary;
@property (nonatomic, strong) MMRecordRepresentation *representation;
@property (nonatomic, strong) NSEntityDescription *entity;
@end
Expand All @@ -42,25 +45,62 @@ + (MMRecordProtoRecord *)protoRecordWithDictionary:(NSDictionary *)dictionary
protoRecord.dictionary = dictionary;
protoRecord.entity = entity;
protoRecord.primaryKeyValue = [representation primaryKeyValueFromDictionary:dictionary];
protoRecord.relationshipProtos = [NSMutableArray array];
protoRecord.relationshipDescriptions = [NSMutableArray array];
protoRecord.relationshipProtosDictionary = [NSMutableDictionary dictionary];
protoRecord.relationshipDescriptionsDictionary = [NSMutableDictionary dictionary];
protoRecord.hasRelationshipPrimarykey = [representation hasRelationshipPrimaryKey];
protoRecord.representation = representation;

return protoRecord;
}

- (NSArray *)relationshipProtos {
NSMutableArray *allRelationshipProtos = [NSMutableArray array];

for (NSOrderedSet *protoSet in [self.relationshipProtosDictionary allValues]) {
[allRelationshipProtos addObjectsFromArray:[protoSet array]];
}

return allRelationshipProtos;
}

#pragma mark - Population
- (NSArray *)relationshipDescriptions {
return [self.relationshipDescriptionsDictionary allValues];
}

- (NSArray *)relationshipProtoRecordsForRelationshipDescription:(NSRelationshipDescription *)relationshipDescription {
NSString *relationshipName = [relationshipDescription name];

NSArray *relationshipProtoRecords = nil;

if (relationshipName != nil) {
NSOrderedSet *protoSet = [self.relationshipProtosDictionary objectForKey:relationshipName];
relationshipProtoRecords = [protoSet array];
}

return relationshipProtoRecords;
}


#pragma mark - Relationships

- (void)addRelationshipProto:(MMRecordProtoRecord *)relationshipProto
forRelationshipDescription:(NSRelationshipDescription *)relationshipDescription {
[(NSMutableArray *)self.relationshipProtos addObject:relationshipProto];
[(NSMutableArray *)self.relationshipDescriptions addObject:relationshipDescription];
NSString *relationshipName = [relationshipDescription name];

if (relationshipName != nil) {
[self.relationshipDescriptionsDictionary setValue:relationshipDescription forKey:relationshipName];


NSMutableOrderedSet *protoSet = [self.relationshipProtosDictionary objectForKey:relationshipName];

if (protoSet == nil) {
protoSet = [NSMutableOrderedSet orderedSet];
}

[protoSet addObject:relationshipProto];

[self.relationshipProtosDictionary setValue:protoSet forKey:relationshipName];
}
}


Expand Down
77 changes: 37 additions & 40 deletions Source/MMRecord/MMRecordResponse.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,17 @@
@interface MMRecordResponseGroup : NSObject

@property (nonatomic, strong) NSEntityDescription *entity;
@property (nonatomic, strong) NSMutableArray *protoRecords;
@property (nonatomic, strong) NSMutableSet *protoRecords;
@property (nonatomic, strong) NSMutableDictionary *prototypeDictionary;
@property (nonatomic, strong) MMRecordRepresentation *representation;
@property (nonatomic) BOOL hasRelationshipPrimaryKey;

- (instancetype)initWithEntity:(NSEntityDescription *)entity;

- (void)addProtoRecord:(MMRecordProtoRecord *)protoRecord;

- (void)addProtoRecordToDictionary:(MMRecordProtoRecord *)protoRecord;

- (MMRecordProtoRecord *)protoRecordForPrimaryKeyValue:(id)primaryKeyValue;

// Will attempt to obtain a record for each proto record using every method possible.
Expand Down Expand Up @@ -155,14 +158,6 @@ - (void)uniquelyAddNewProtoRecord:(MMRecordProtoRecord *)protoRecord
fromExistingResponseGroups:responseGroups];

[responseGroup addProtoRecord:protoRecord];

for (MMRecordProtoRecord *relationshipProtoRecord in protoRecord.relationshipProtos) {
MMRecordResponseGroup *relationshipProtoRecordResponseGroup = [self responseGroupForEntity:relationshipProtoRecord.entity
fromExistingResponseGroups:responseGroups];

[relationshipProtoRecordResponseGroup addProtoRecord:relationshipProtoRecord];
[self uniquelyAddNewProtoRecord:relationshipProtoRecord toExistingResponseGroups:responseGroups];
}
}


Expand Down Expand Up @@ -193,7 +188,6 @@ - (void)buildProtoRecordsAndResponseGroups {
existingResponseGroups:responseGroups];

[objectGraph addObject:proto];
[self uniquelyAddNewProtoRecord:proto toExistingResponseGroups:responseGroups];
}

self.objectGraph = objectGraph;
Expand All @@ -205,7 +199,8 @@ - (void)buildProtoRecordsAndResponseGroups {
- (MMRecordProtoRecord *)protoRecordWithRecordResponseObject:(id)recordResponseObject
entity:(NSEntityDescription *)entity
existingResponseGroups:(NSMutableDictionary *)responseGroups {
MMRecordResponseGroup *recordResponseGroup = [self responseGroupForEntity:entity fromExistingResponseGroups:responseGroups];
MMRecordResponseGroup *recordResponseGroup = [self responseGroupForEntity:entity
fromExistingResponseGroups:responseGroups];
MMRecordRepresentation *representation = recordResponseGroup.representation;

if ([recordResponseObject isKindOfClass:[NSDictionary class]] == NO) {
Expand All @@ -216,14 +211,19 @@ - (MMRecordProtoRecord *)protoRecordWithRecordResponseObject:(id)recordResponseO
MMRecordProtoRecord *proto = [recordResponseGroup protoRecordForPrimaryKeyValue:primaryValue];

if (proto == nil) {
proto = [MMRecordProtoRecord protoRecordWithDictionary:recordResponseObject entity:entity representation:representation];
[self uniquelyAddNewProtoRecord:proto toExistingResponseGroups:responseGroups];
proto = [MMRecordProtoRecord protoRecordWithDictionary:recordResponseObject
entity:entity
representation:representation];
}

[self uniquelyAddNewProtoRecord:proto toExistingResponseGroups:responseGroups];

if (proto) {
[self completeRelationshipProtoRecordMappingToProtoRecord:proto
existingResponseGroups:responseGroups
representation:representation];

[recordResponseGroup addProtoRecordToDictionary:proto];
}

return proto;
Expand Down Expand Up @@ -267,7 +267,7 @@ - (void)addRelationshipProtoRecordsToProtoRecord:(MMRecordProtoRecord *)protoRec
entity:entity
existingResponseGroups:responseGroups];

[protoRecord addRelationshipProto:relationshipProto forRelationshipDescription:relationshipDescription];
[protoRecord addRelationshipProto:relationshipProto forRelationshipDescription:relationshipDescription];
}
}
}
Expand Down Expand Up @@ -311,32 +311,35 @@ - (id)initWithEntity:(NSEntityDescription *)entity {
if (self = [super init]) {
NSParameterAssert([NSClassFromString([entity managedObjectClassName]) isSubclassOfClass:[MMRecord class]]);
_entity = entity;
_protoRecords = [NSMutableArray array];
_protoRecords = [NSMutableSet set];

Class MMRecordClass = NSClassFromString([entity managedObjectClassName]);
Class MMRecordRepresentationClass = [MMRecordClass representationClass];

_representation = [[MMRecordRepresentationClass alloc] initWithEntity:entity];
_hasRelationshipPrimaryKey = [_representation hasRelationshipPrimaryKey];
_prototypeDictionary = [NSMutableDictionary dictionary];
}
return self;
}

- (void)addProtoRecord:(MMRecordProtoRecord *)protoRecord {
[self.protoRecords addObject:protoRecord];
if ([self.prototypeDictionary objectForKey:protoRecord.primaryKeyValue] == nil) {
[self.protoRecords addObject:protoRecord];
}
}

- (void)addProtoRecordToDictionary:(MMRecordProtoRecord *)protoRecord {
if (protoRecord.primaryKeyValue) {
self.prototypeDictionary[protoRecord.primaryKeyValue] = protoRecord;
}
}


#pragma mark - Accessors

- (MMRecordProtoRecord *)protoRecordForPrimaryKeyValue:(id)primaryKeyValue {
for (MMRecordProtoRecord *proto in self.protoRecords) {
if ([proto.primaryKeyValue isEqual:primaryKeyValue]) {
return proto;
}
}

return nil;
return [self.prototypeDictionary objectForKey:primaryKeyValue];
}


Expand Down Expand Up @@ -394,25 +397,18 @@ - (void)performFetchForAllRecordsAndAssociateWithProtosInContext:(NSManagedObjec
}

NSArray *existingRecords = [self fetchRecordsWithPrimaryKeys:allPrimaryKeys forEntity:self.entity context:context];
NSArray *sortedProtoRecords = [self sortedProtoRecordsByPrimaryKeyValueInAscendingOrder:self.protoRecords];
NSArray *sortedProtoRecords = [self sortedProtoRecordsByPrimaryKeyValueInAscendingOrder:[self.protoRecords allObjects]];

NSMutableDictionary *existingRecordDictionary = [[NSMutableDictionary alloc] init];

for (MMRecord *record in existingRecords) {
id recordPrimaryKeyValue = [record primaryKeyValue];
[existingRecordDictionary setObject:record forKey:record.primaryKeyValue];
}

for (MMRecordProtoRecord *protoRecord in sortedProtoRecords) {
id protoRecordPrimaryKeyValue = protoRecord.primaryKeyValue;

for (MMRecordProtoRecord *protoRecord in sortedProtoRecords) {
id protoRecordPrimaryKeyValue = protoRecord.primaryKeyValue;
NSComparisonResult comparisonResult = [self comparePrimaryKeyValues:recordPrimaryKeyValue
protoRecordPrimaryKeyValue:protoRecordPrimaryKeyValue];

if (comparisonResult == NSOrderedSame) {
protoRecord.record = record;
break;
} else if (comparisonResult == NSOrderedAscending) {
break;
} else if (comparisonResult == NSOrderedDescending) {
// Continue
}
}
protoRecord.record = [existingRecordDictionary objectForKey:protoRecordPrimaryKeyValue];
}
}

Expand Down Expand Up @@ -454,6 +450,7 @@ - (NSArray*)fetchRecordsWithPrimaryKeys:(NSArray *)primaryKeys forEntity:(NSEnti
return nil;

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:[entity name]];
[fetchRequest setFetchBatchSize:20];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:primaryAttributeKey ascending:YES]];
fetchRequest.predicate = [NSPredicate predicateWithFormat: @"SELF.%@ IN %@", primaryAttributeKey, primaryKeys];

Expand Down Expand Up @@ -488,4 +485,4 @@ - (void)createRecordsForProtoRecordsWithMissingRecordsInContext:(NSManagedObject
#undef MMRLogInfo
#undef MMRLogWarn
#undef MMRLogError
#undef MMRLogVerbose
#undef MMRLogVerbose
6 changes: 6 additions & 0 deletions Source/MMRecordJSONServer/MMJSONServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@
*/
+ (NSTimeInterval)simulatedServerDelayTime;

/**
This method allows you to load a specified JSON file with a given resource name.
@param resourceName The name of the JSON file you want to load.
@param responseBlock The response block to be executed with the contents of the file.
@param failureBlock The failure block to be called in the event of an error.
*/
+ (void)loadJSONResource:(NSString *)resourceName
responseBlock:(void(^)(NSDictionary *responseData))responseBlock
failureBlock:(void(^)(NSError *error))failureBlock;
Expand Down

0 comments on commit 25b7749

Please sign in to comment.