Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix slow [factory registerDefinition:] method. #330

Merged
merged 2 commits into from
Mar 19, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions Source/Configuration/TyphoonDefinitionPostProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import <Foundation/Foundation.h>

@class TyphoonComponentFactory;
@class TyphoonDefinition;

/**
* @ingroup Assembly
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -46,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<TyphoonPropertyInjection> 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<TyphoonPropertyInjection> 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))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <TyphoonInjection> *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 <TyphoonInjection> *injectionToReplace, BOOL *stop) {
if ([self shouldReplaceInjectionByType:typeInjection withFactoryInjectionInDefinition:definition]) {
*injectionToReplace = [self factoryInjectionToReplacePropertyInjection:typeInjection];
}
}];
}

//-------------------------------------------------------------------------------------------
#pragma mark - Instance Methods

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 10 additions & 1 deletion Source/Factory/TyphoonComponentFactory.m
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ - (void)registerDefinition:(TyphoonDefinition *)definition
[registerer doRegistration];

if ([self isLoaded]) {
[self _load];
[self _loadOnlyOne:definition];
}
}

Expand Down Expand Up @@ -291,6 +291,15 @@ - (void)_load
[self instantiateEagerSingletons];
}

- (void)_loadOnlyOne:(TyphoonDefinition *)definition
{
[self preparePostProcessors];
[_definitionPostProcessors enumerateObjectsUsingBlock:^(id<TyphoonDefinitionPostProcessor> postProcessor, NSUInteger idx, BOOL *stop) {
[postProcessor postProcessDefinition:definition withFactory:self];
}];
[self newOrScopeCachedInstanceForDefinition:definition args:nil];
}

- (NSArray *)orderedArray:(NSMutableArray *)array
{
return [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
Expand Down
4 changes: 4 additions & 0 deletions Source/Utils/TyphoonIntrospectionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
94 changes: 86 additions & 8 deletions Source/Utils/TyphoonIntrospectionUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,47 @@
#import <objc/message.h>
#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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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];
}

Expand All @@ -129,6 +193,8 @@ + (NSSet *)propertiesForClass:(Class)clazz upToParentClass:(Class)parent
free(properties);
}

[propertiesCache setObject:propertyNames forKey:key];

return propertyNames;
}

Expand All @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ - (void)postProcessDefinitionsInFactory:(TyphoonComponentFactory *)factory
self.postProcessingCalled = YES;
}

- (void)postProcessDefinition:(TyphoonDefinition *)definition withFactory:(TyphoonComponentFactory *)factory
{
self.postProcessingCalled = YES;
}

@end