From 4d550961b53e6f5f65914db54da48007451e31c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Varga=20Bala=CC=81zs?= Date: Tue, 10 Mar 2015 15:47:48 +0100 Subject: [PATCH 1/2] Fix slow [factory registerDefinition:] method. --- .../TyphoonConfigPostProcessor.m | 9 +++++++-- ...ctDetachableComponentFactoryPostProcessor.m | 6 ++++++ .../TyphoonDefinitionPostProcessor.h | 8 ++++++++ .../TyphoonFactoryAutoInjectionPostProcessor.m | 5 +++++ ...hoonFactoryPropertyInjectionPostProcessor.m | 18 +++++++++++------- ...hoonParentReferenceHydratingPostProcessor.m | 14 ++++++++++---- Source/Factory/TyphoonComponentFactory.m | 11 ++++++++++- .../TyphoonViewControllerNibResolver.m | 11 ++++++++--- ...hoonComponentFactoryPostProcessorStubImpl.m | 5 +++++ 9 files changed, 70 insertions(+), 17 deletions(-) diff --git a/Source/Configuration/ConfigPostProcessor/TyphoonConfigPostProcessor.m b/Source/Configuration/ConfigPostProcessor/TyphoonConfigPostProcessor.m index fcb9fefef..537986381 100644 --- a/Source/Configuration/ConfigPostProcessor/TyphoonConfigPostProcessor.m +++ b/Source/Configuration/ConfigPostProcessor/TyphoonConfigPostProcessor.m @@ -133,11 +133,16 @@ - (id)configurationValueForKey:(NSString *)key - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory { for (TyphoonDefinition *definition in [factory registry]) { - [self configureInjectionsInDefinition:definition]; - [self configureInjectionsInRuntimeArgumentsInDefinition:definition]; + [self postProcessDefinition:definition withFactory:factory]; } } +- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory +{ + [self configureInjectionsInDefinition:definition]; + [self configureInjectionsInRuntimeArgumentsInDefinition:definition]; +} + - (void)configureInjectionsInDefinition:(TyphoonDefinition *)definition { [definition enumerateInjectionsOfKind:[TyphoonInjectionByConfig class] options:TyphoonInjectionsEnumerationOptionAll diff --git a/Source/Configuration/TyphoonAbstractDetachableComponentFactoryPostProcessor.m b/Source/Configuration/TyphoonAbstractDetachableComponentFactoryPostProcessor.m index 0cd8eb2eb..69bd8062e 100644 --- a/Source/Configuration/TyphoonAbstractDetachableComponentFactoryPostProcessor.m +++ b/Source/Configuration/TyphoonAbstractDetachableComponentFactoryPostProcessor.m @@ -31,6 +31,12 @@ - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory [self cacheDefinitionsIn:_factory]; } +- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory +{ + _factory = factory; + [self cacheDefinitionsIn:_factory]; +} + - (void)rollback { NSMutableArray *postProcessors = (NSMutableArray *) _factory.definitionPostProcessors; diff --git a/Source/Configuration/TyphoonDefinitionPostProcessor.h b/Source/Configuration/TyphoonDefinitionPostProcessor.h index 2f0709248..baebc6603 100644 --- a/Source/Configuration/TyphoonDefinitionPostProcessor.h +++ b/Source/Configuration/TyphoonDefinitionPostProcessor.h @@ -13,6 +13,7 @@ #import @class TyphoonComponentFactory; +@class TyphoonDefinition; /** * @ingroup Assembly @@ -35,4 +36,11 @@ */ - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory; +/** + TODO. + @param definition The definition. + @param factory The component factory. + */ +- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory; + @end diff --git a/Source/Definition/AutoInjection/TyphoonFactoryAutoInjectionPostProcessor.m b/Source/Definition/AutoInjection/TyphoonFactoryAutoInjectionPostProcessor.m index 4091c8dd3..b1a5508c1 100644 --- a/Source/Definition/AutoInjection/TyphoonFactoryAutoInjectionPostProcessor.m +++ b/Source/Definition/AutoInjection/TyphoonFactoryAutoInjectionPostProcessor.m @@ -32,6 +32,11 @@ - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory } } +- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory +{ + [self postProcessDefinition:definition]; +} + - (void)postProcessDefinition:(TyphoonDefinition *)definition { Class clazz = definition.type; diff --git a/Source/Factory/Internal/TyphoonFactoryPropertyInjectionPostProcessor.m b/Source/Factory/Internal/TyphoonFactoryPropertyInjectionPostProcessor.m index 42f1cc606..372049a52 100644 --- a/Source/Factory/Internal/TyphoonFactoryPropertyInjectionPostProcessor.m +++ b/Source/Factory/Internal/TyphoonFactoryPropertyInjectionPostProcessor.m @@ -27,16 +27,20 @@ @implementation TyphoonFactoryPropertyInjectionPostProcessor - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory { for (TyphoonDefinition *definition in [factory registry]) { - - [definition enumerateInjectionsOfKind:[TyphoonInjectionByType class] options:TyphoonInjectionsEnumerationOptionProperties - usingBlock:^(TyphoonInjectionByType *typeInjection, id *injectionToReplace, BOOL *stop) { - if ([self shouldReplaceInjectionByType:typeInjection withFactoryInjectionInDefinition:definition]) { - *injectionToReplace = [self factoryInjectionToReplacePropertyInjection:typeInjection]; - } - }]; + [self postProcessDefinition:definition withFactory:factory]; } } +- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory +{ + [definition enumerateInjectionsOfKind:[TyphoonInjectionByType class] options:TyphoonInjectionsEnumerationOptionProperties + usingBlock:^(TyphoonInjectionByType *typeInjection, id *injectionToReplace, BOOL *stop) { + if ([self shouldReplaceInjectionByType:typeInjection withFactoryInjectionInDefinition:definition]) { + *injectionToReplace = [self factoryInjectionToReplacePropertyInjection:typeInjection]; + } + }]; +} + //------------------------------------------------------------------------------------------- #pragma mark - Instance Methods diff --git a/Source/Factory/Internal/TyphoonParentReferenceHydratingPostProcessor.m b/Source/Factory/Internal/TyphoonParentReferenceHydratingPostProcessor.m index 154c3d477..cc543c2a7 100644 --- a/Source/Factory/Internal/TyphoonParentReferenceHydratingPostProcessor.m +++ b/Source/Factory/Internal/TyphoonParentReferenceHydratingPostProcessor.m @@ -21,12 +21,18 @@ @implementation TyphoonParentReferenceHydratingPostProcessor - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory { [factory.registry enumerateObjectsUsingBlock:^(TyphoonDefinition *definition, NSUInteger idx, BOOL *stop) { - if (definition.parent) { - TyphoonDefinition *parentDefinition = [factory definitionForKey:[(TyphoonDefinition *)definition.parent key]]; - [definition setParent:parentDefinition]; - } + [self postProcessDefinition:definition withFactory:factory]; }]; } +- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory +{ + if (definition.parent) { + TyphoonDefinition *parentDefinition = [factory definitionForKey:[(TyphoonDefinition *)definition.parent key]]; + [definition setParent:parentDefinition]; + } + +} + @end \ No newline at end of file diff --git a/Source/Factory/TyphoonComponentFactory.m b/Source/Factory/TyphoonComponentFactory.m index 8231a4bc7..21b3d87d2 100644 --- a/Source/Factory/TyphoonComponentFactory.m +++ b/Source/Factory/TyphoonComponentFactory.m @@ -134,7 +134,7 @@ - (void)registerDefinition:(TyphoonDefinition *)definition [registerer doRegistration]; if ([self isLoaded]) { - [self _load]; + [self _loadOnlyOne:definition]; } } @@ -291,6 +291,15 @@ - (void)_load [self instantiateEagerSingletons]; } +- (void)_loadOnlyOne:(TyphoonDefinition *)definition +{ + [self preparePostProcessors]; + [_definitionPostProcessors enumerateObjectsUsingBlock:^(id postProcessor, NSUInteger idx, BOOL *stop) { + [postProcessor postProcessDefinition:definition withFactory:self]; + }]; + [self instantiateEagerSingletons]; +} + - (NSArray *)orderedArray:(NSMutableArray *)array { return [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { diff --git a/Source/ios/Configuration/Resolver/TyphoonViewControllerNibResolver.m b/Source/ios/Configuration/Resolver/TyphoonViewControllerNibResolver.m index ebc9adbfd..e76bb64b1 100644 --- a/Source/ios/Configuration/Resolver/TyphoonViewControllerNibResolver.m +++ b/Source/ios/Configuration/Resolver/TyphoonViewControllerNibResolver.m @@ -23,9 +23,14 @@ @implementation TyphoonViewControllerNibResolver - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory { for (TyphoonDefinition *definition in [factory registry]) { - if ([self shouldProcessDefinition:definition]) { - [self processViewControllerDefinition:definition]; - } + [self postProcessDefinition:definition withFactory:factory]; + } +} + +- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory +{ + if ([self shouldProcessDefinition:definition]) { + [self processViewControllerDefinition:definition]; } } diff --git a/Tests/Configuration/TyphoonComponentFactoryPostProcessorStubImpl.m b/Tests/Configuration/TyphoonComponentFactoryPostProcessorStubImpl.m index 5342c5639..496c07aa3 100644 --- a/Tests/Configuration/TyphoonComponentFactoryPostProcessorStubImpl.m +++ b/Tests/Configuration/TyphoonComponentFactoryPostProcessorStubImpl.m @@ -18,4 +18,9 @@ - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory self.postProcessingCalled = YES; } +- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory +{ + self.postProcessingCalled = YES; +} + @end From cced1230e51fea86422469a9244e434d6e242f74 Mon Sep 17 00:00:00 2001 From: Balazs Varga Date: Wed, 18 Mar 2015 16:13:12 +0100 Subject: [PATCH 2/2] Cache properties for classes and optimized injected property searching. --- ...TyphoonFactoryAutoInjectionPostProcessor.m | 28 ++---- Source/Factory/TyphoonComponentFactory.m | 2 +- Source/Utils/TyphoonIntrospectionUtils.h | 4 + Source/Utils/TyphoonIntrospectionUtils.m | 94 +++++++++++++++++-- 4 files changed, 101 insertions(+), 27 deletions(-) diff --git a/Source/Definition/AutoInjection/TyphoonFactoryAutoInjectionPostProcessor.m b/Source/Definition/AutoInjection/TyphoonFactoryAutoInjectionPostProcessor.m index b1a5508c1..e543ccd26 100644 --- a/Source/Definition/AutoInjection/TyphoonFactoryAutoInjectionPostProcessor.m +++ b/Source/Definition/AutoInjection/TyphoonFactoryAutoInjectionPostProcessor.m @@ -51,31 +51,23 @@ - (void)postProcessDefinition:(TyphoonDefinition *)definition - (NSArray *)autoInjectedPropertiesForClass:(Class)clazz { NSMutableArray *injections = nil; - NSSet *allProperties = [TyphoonIntrospectionUtils propertiesForClass:clazz upToParentClass:[NSObject class]]; + NSSet *allProperties = [TyphoonIntrospectionUtils injectedPropertiesForClass:clazz upToParentClass:[NSObject class]]; for (NSString *propertyName in allProperties) { TyphoonTypeDescriptor *type = [clazz typhoon_typeForPropertyWithName:propertyName]; - if (IsTyphoonAutoInjectionType(type)) { - id explicitType = TypeForInjectionFromType(type); - if (!explicitType) { - [NSException raise:NSInternalInconsistencyException format:@"Can't resolve '%@' property in %@ class. Make sure that specified protocol/class exist and linked.", propertyName, clazz]; - } - id injection = TyphoonInjectionWithType(explicitType); - [injection setPropertyName:propertyName]; - if (!injections) { - injections = [[NSMutableArray alloc] initWithCapacity:allProperties.count]; - } - [injections addObject:injection]; + id explicitType = TypeForInjectionFromType(type); + if (!explicitType) { + [NSException raise:NSInternalInconsistencyException format:@"Can't resolve '%@' property in %@ class. Make sure that specified protocol/class exist and linked.", propertyName, clazz]; } + id injection = TyphoonInjectionWithType(explicitType); + [injection setPropertyName:propertyName]; + if (!injections) { + injections = [[NSMutableArray alloc] initWithCapacity:allProperties.count]; + } + [injections addObject:injection]; } return injections; } -static BOOL IsTyphoonAutoInjectionType(TyphoonTypeDescriptor *type) -{ - return protocol_isEqual(type.protocol, @protocol(TyphoonInjectedProtocol)) || - type.typeBeingDescribed == [TyphoonInjectedObject class]; -} - static id TypeForInjectionFromType(TyphoonTypeDescriptor *type) { if (protocol_isEqual(type.protocol, @protocol(TyphoonInjectedProtocol))) { diff --git a/Source/Factory/TyphoonComponentFactory.m b/Source/Factory/TyphoonComponentFactory.m index 21b3d87d2..790c19224 100644 --- a/Source/Factory/TyphoonComponentFactory.m +++ b/Source/Factory/TyphoonComponentFactory.m @@ -297,7 +297,7 @@ - (void)_loadOnlyOne:(TyphoonDefinition *)definition [_definitionPostProcessors enumerateObjectsUsingBlock:^(id postProcessor, NSUInteger idx, BOOL *stop) { [postProcessor postProcessDefinition:definition withFactory:self]; }]; - [self instantiateEagerSingletons]; + [self newOrScopeCachedInstanceForDefinition:definition args:nil]; } - (NSArray *)orderedArray:(NSMutableArray *)array diff --git a/Source/Utils/TyphoonIntrospectionUtils.h b/Source/Utils/TyphoonIntrospectionUtils.h index 2ca615ffd..2cab301ce 100644 --- a/Source/Utils/TyphoonIntrospectionUtils.h +++ b/Source/Utils/TyphoonIntrospectionUtils.h @@ -27,6 +27,8 @@ BOOL IsProtocol(id classOrProtocol); @interface TyphoonIntrospectionUtils : NSObject ++ (TyphoonTypeDescriptor *)typeForProperty:(objc_property_t)property; + + (TyphoonTypeDescriptor *)typeForPropertyWithName:(NSString *)propertyName inClass:(Class)clazz; + (SEL)setterForPropertyWithName:(NSString *)property inClass:(Class)clazz; @@ -36,6 +38,8 @@ BOOL IsProtocol(id classOrProtocol); + (NSUInteger)numberOfArgumentsInSelector:(SEL)selector; ++ (NSSet *)injectedPropertiesForClass:(Class)clazz upToParentClass:(Class)parent; + + (NSSet *)propertiesForClass:(Class)clazz upToParentClass:(Class)parent; + (NSSet *)methodsForClass:(Class)clazz upToParentClass:(Class)parent; diff --git a/Source/Utils/TyphoonIntrospectionUtils.m b/Source/Utils/TyphoonIntrospectionUtils.m index c0c40237a..b5fe65df4 100644 --- a/Source/Utils/TyphoonIntrospectionUtils.m +++ b/Source/Utils/TyphoonIntrospectionUtils.m @@ -16,36 +16,47 @@ #import #import "TyphoonIntrospectionUtils.h" #import "TyphoonTypeDescriptor.h" +#import "TyphoonInjectedObject.h" + +static NSMutableDictionary * injectedPropertiesCache = nil; +static NSMutableDictionary * propertiesCache = nil; @implementation TyphoonIntrospectionUtils -+ (TyphoonTypeDescriptor *)typeForPropertyWithName:(NSString *)propertyName inClass:(Class)clazz ++ (TyphoonTypeDescriptor *)typeForProperty:(objc_property_t)property { TyphoonTypeDescriptor *typeDescriptor = nil; - objc_property_t propertyReflection = class_getProperty(clazz, [propertyName cStringUsingEncoding:NSASCIIStringEncoding]); - if (propertyReflection) { - const char *attributes = property_getAttributes(propertyReflection); - + + if (property) { + const char *attributes = property_getAttributes(property); + if (attributes == NULL) { return (NULL); } - + static char buffer[256]; const char *e = strchr(attributes, ','); if (e == NULL) { return (NULL); } - + int len = (int) (e - attributes); memcpy( buffer, attributes, len ); buffer[len] = '\0'; - + NSString *typeCode = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding]; typeDescriptor = [TyphoonTypeDescriptor descriptorWithTypeCode:typeCode]; } return typeDescriptor; } + ++ (TyphoonTypeDescriptor *)typeForPropertyWithName:(NSString *)propertyName inClass:(Class)clazz +{ + objc_property_t propertyReflection = class_getProperty(clazz, [propertyName cStringUsingEncoding:NSASCIIStringEncoding]); + return [self typeForProperty:propertyReflection]; +} + + (SEL)setterForPropertyWithName:(NSString *)propertyName inClass:(Class)clazz { SEL setterSelector = nil; @@ -110,8 +121,60 @@ + (NSUInteger)numberOfArgumentsInSelector:(SEL)selector return count; } ++ (NSSet *)injectedPropertiesForClass:(Class)clazz upToParentClass:(Class)parent +{ + NSString *key = NSStringFromClass(clazz); + if (injectedPropertiesCache == nil) { + injectedPropertiesCache = [NSMutableDictionary dictionary]; + } else { + if ([[injectedPropertiesCache allKeys] containsObject:key]) { + return [injectedPropertiesCache objectForKey:key]; + } + } + + NSMutableSet *propertyNames = [[NSMutableSet alloc] init]; + + NSString *injectedObjectClassName = NSStringFromClass([TyphoonInjectedObject class]); + NSString *injectedProtolName = NSStringFromProtocol(@protocol(TyphoonInjectedProtocol)); + + while (clazz != parent) { + unsigned int count = 0; + objc_property_t *properties = class_copyPropertyList(clazz, &count); + + for (unsigned int propertyIndex = 0; propertyIndex < count; propertyIndex++) { + objc_property_t aProperty = properties[propertyIndex]; + NSString *propertyName = [NSString stringWithCString:property_getName(aProperty) encoding:NSUTF8StringEncoding]; + + NSString *className = [self classNameOfProperty:aProperty]; + + // Little bit faster than protocol_isEqual method. + if ([className containsString:injectedObjectClassName] || [className containsString:injectedProtolName]) { + [propertyNames addObject:propertyName]; + } + } + + clazz = class_getSuperclass(clazz); + + free(properties); + } + + [injectedPropertiesCache setObject:propertyNames forKey:key]; + + return propertyNames; +} + + (NSSet *)propertiesForClass:(Class)clazz upToParentClass:(Class)parent { + NSString *key = NSStringFromClass(clazz); + + if (propertiesCache == nil) { + propertiesCache = [NSMutableDictionary dictionary]; + } else { + if ([[propertiesCache allKeys] containsObject:key]) { + return [propertiesCache objectForKey:key]; + } + } + NSMutableSet *propertyNames = [[NSMutableSet alloc] init]; while (clazz != parent) { @@ -121,6 +184,7 @@ + (NSSet *)propertiesForClass:(Class)clazz upToParentClass:(Class)parent for (unsigned int propertyIndex = 0; propertyIndex < count; propertyIndex++) { objc_property_t aProperty = properties[propertyIndex]; NSString *propertyName = [NSString stringWithCString:property_getName(aProperty) encoding:NSUTF8StringEncoding]; + [propertyNames addObject:propertyName]; } @@ -129,6 +193,8 @@ + (NSSet *)propertiesForClass:(Class)clazz upToParentClass:(Class)parent free(properties); } + [propertiesCache setObject:propertyNames forKey:key]; + return propertyNames; } @@ -152,6 +218,18 @@ + (NSSet *)methodsForClass:(Class)clazz upToParentClass:(Class)parent #pragma mark - Property Attributes Utils ++ (NSString *)classNameOfProperty:(objc_property_t)property +{ + NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding]; + NSArray *splitPropertyAttributes = [propertyAttributes componentsSeparatedByString:@"\""]; + if (splitPropertyAttributes.count >= 2) { + + return [splitPropertyAttributes objectAtIndex:1]; + } + + return nil; +} + + (BOOL)isReadonlyProperty:(objc_property_t)property { char *readonlyFlag = property_copyAttributeValue(property, "R");