Skip to content

Commit

Permalink
Working on reference-counting problems with ARC when building instance
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgarbarev committed Jan 28, 2014
1 parent fc4cbf6 commit f32c6c1
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

- (NSInvocation*)asInvocationFor:(id)classOrInstance;

- (NSMethodSignature *) methodSignatureForClass:(Class)clazz;

- (void)setComponentDefinition:(TyphoonDefinition*)definition;


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ - (NSInvocation*)asInvocationFor:(id)classOrInstance
return invocation;
}

- (NSMethodSignature *) methodSignatureForClass:(Class)clazz
{
NSMethodSignature *signature = nil;

if (self.isClassMethod) {
signature = [clazz methodSignatureForSelector:_selector];
} else {
signature = [clazz instanceMethodSignatureForSelector:_selector];
}

return signature;
}


- (void)setComponentDefinition:(TyphoonDefinition*)definition
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@

- (id)initWithParameterIndex:(NSUInteger)index value:(id)value;

- (BOOL) isPrimitiveParameterFor:(id)classOrInstance;
- (BOOL) isPrimitiveParameterForClass:(Class)aClass isClassMethod:(BOOL)isClassMethod;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,9 @@ - (void)setInitializer:(TyphoonInitializer*)initializer
/* ====================================================================================================================================== */
#pragma mark - Interface Methods

- (BOOL) isPrimitiveParameterFor:(id)classOrInstance
{
BOOL isClass = class_isMetaClass(object_getClass(classOrInstance));

Class class = isClass ? classOrInstance : [classOrInstance class];

NSArray* typeCodes = [TyphoonIntrospectionUtils typeCodesForSelector:_initializer.selector ofClass:class isClassMethod:isClass];
- (BOOL) isPrimitiveParameterForClass:(Class)aClass isClassMethod:(BOOL)isClassMethod
{
NSArray* typeCodes = [TyphoonIntrospectionUtils typeCodesForSelector:_initializer.selector ofClass:aClass isClassMethod:isClassMethod];

return ![[typeCodes objectAtIndex:_index] isEqualToString:@"@"];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@
*/
- (TyphoonTypeDescriptor*)resolveTypeWith:(id)classOrInstance;

- (TyphoonTypeDescriptor*)resolveTypeWith:(Class)clazz isClassMethod:(BOOL)isClassMethod;


@end
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,24 @@ - (TyphoonTypeDescriptor*)resolveTypeWith:(id)classOrInstance
}
}

- (TyphoonTypeDescriptor*)resolveTypeWith:(Class)clazz isClassMethod:(BOOL)isClassMethod
{
if (_requiredType)
{
return [TyphoonTypeDescriptor descriptorWithClassOrProtocol:_requiredType];
}
else
{
NSArray* typeCodes = [TyphoonIntrospectionUtils typeCodesForSelector:_initializer.selector ofClass:clazz isClassMethod:isClassMethod];

if ([[typeCodes objectAtIndex:_index] isEqualToString:@"@"])
{
[NSException raise:NSInvalidArgumentException
format:@"Unless the type is primitive (int, BOOL, etc), initializer injection requires the required class to be specified. Eg: <argument parameterName=\"string\" value=\"http://dev.foobar.com/service/\" required-class=\"NSString\" />"];
}
return [TyphoonTypeDescriptor descriptorWithTypeCode:[typeCodes objectAtIndex:_index]];
}
}

/* ====================================================================================================================================== */
#pragma mark - Protocol Methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
*/
@interface TyphoonComponentFactory (InstanceBuilder)

- (id)buildInstanceWithDefinition:(TyphoonDefinition*)definition;
- (id)newInstanceWithDefinition:(TyphoonDefinition*)definition;

- (id)buildSharedInstanceForDefinition:(TyphoonDefinition*)definition;
- (id)newSharedInstanceForDefinition:(TyphoonDefinition*)definition;

- (void)injectPropertyDependenciesOn:(__autoreleasing id)instance withDefinition:(TyphoonDefinition*)definition;

Expand Down
195 changes: 137 additions & 58 deletions Source/Factory/Internal/TyphoonComponentFactory+InstanceBuilder.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,21 @@ @implementation TyphoonComponentFactory (InstanceBuilder)
/* ====================================================================================================================================== */
#pragma mark - Initialization & Destruction

- (id)buildInstanceWithDefinition:(TyphoonDefinition*)definition
- (id)newInstanceWithDefinition:(TyphoonDefinition*)definition
{
__autoreleasing id <TyphoonIntrospectiveNSObject> instance = [self allocateInstanceWithDefinition:definition];
id <TyphoonIntrospectiveNSObject> instance = nil;

instance = [self newInitializedInstanceWithDefinition:definition];
[_stack push:[TyphoonStackElement itemWithKey:definition.key instance:instance]];
instance = [self injectInstance:instance withDefinition:definition];
instance = [self postProcessInstance:instance];
[self injectPropertyDependenciesOn:instance withDefinition:definition];
[_stack pop];

instance = [self postProcessInstance:instance];

return instance;
}

- (id)allocateInstanceWithDefinition:(TyphoonDefinition*)definition
- (id) newInitializedInstanceWithDefinition:(TyphoonDefinition*)definition NS_RETURNS_RETAINED
{
id instance = nil;

Expand All @@ -73,32 +77,38 @@ - (id)allocateInstanceWithDefinition:(TyphoonDefinition*)definition
// about.
instance = [self componentForKey:definition.factoryReference]; // clears currently resolving.
}
else if (definition.initializer && definition.initializer.isClassMethod)
{
// this is an instance of the class, needing no more init.
instance = [self invokeInitializer:definition.initializer on:definition.type];
}
else
{
// this is an instance, needing later init.
/* FIXME: sending init on another line than alloc is wrong, see apple docs */
instance = [definition.type alloc];
/* Sending init later after alloc is wrong, see http://www.foldr.org/~michaelw/objective-c/ObjectiveC/5RunTime/Allocation__tialization.html
* It is reason to refactor */

NSInvocation *invocation = [self invocationToInitDefinition:definition];

if (definition.initializer && definition.initializer.isClassMethod) {
[invocation setTarget:definition.type];
} else {
[invocation setTarget:[definition.type alloc]];
}

[invocation invoke];
[invocation getReturnValue:&instance];
}



[self handleSpecialCaseForNSManagedObjectModel:instance];

return instance;
}


- (id)injectInstance:(id)instance withDefinition:(TyphoonDefinition*)definition
{
instance = [self initializerInjectionOn:instance withDefinition:definition];
[_stack push:[TyphoonStackElement itemWithKey:definition.key instance:instance]];
[self injectPropertyDependenciesOn:instance withDefinition:definition];
[_stack pop];
return instance;
}
//- (id)injectInstance:(id)instance withDefinition:(TyphoonDefinition*)definition UNAVAILABLE_ATTRIBUTE
//{
// instance = [self initializerInjectionOn:instance withDefinition:definition];
// [_stack push:[TyphoonStackElement itemWithKey:definition.key instance:instance]];
// [self injectPropertyDependenciesOn:instance withDefinition:definition];
// [_stack pop];
// return instance;
//}

- (id)postProcessInstance:(id)instance
{
Expand All @@ -112,26 +122,26 @@ - (id)postProcessInstance:(id)instance
return instance;
}

- (id)initializerInjectionOn:(id)instance withDefinition:(TyphoonDefinition*)definition
{
if (definition.initializer)
{
if (definition.initializer.isClassMethod == NO)
{
instance = [self invokeInitializer:definition.initializer on:instance];
}
else
{
// initializer was already invoked in allocateInstance:withDefinition:
}
}
else if (definition.initializer == nil)
{
instance = [self invokeDefaultInitializerOn:instance];
}

return instance;
}
//- (id)initializerInjectionOn:(id)instance withDefinition:(TyphoonDefinition*)definition UNAVAILABLE_ATTRIBUTE
//{
// if (definition.initializer)
// {
// if (definition.initializer.isClassMethod == NO)
// {
// instance = [self invokeInitializer:definition.initializer on:instance];
// }
// else
// {
// // initializer was already invoked in allocateInstance:withDefinition:
// }
// }
// else if (definition.initializer == nil)
// {
// instance = [self invokeDefaultInitializerOn:instance];
// }
//
// return instance;
//}

- (id)invokeDefaultInitializerOn:(id)instance
{
Expand All @@ -152,13 +162,13 @@ - (void)injectAssemblyOnInstance:(id <TyphoonComponentFactoryAware>)instance;
[instance setFactory:self];
}

- (id)buildSharedInstanceForDefinition:(TyphoonDefinition*)definition
- (id)newSharedInstanceForDefinition:(TyphoonDefinition*)definition
{
if ([self alreadyResolvingKey:definition.key])
{
return [_stack peekForKey:definition.key].instance;
}
return [self buildInstanceWithDefinition:definition];
return [self newInstanceWithDefinition:definition];
}


Expand All @@ -170,7 +180,7 @@ - (BOOL)alreadyResolvingKey:(NSString*)key
/* ====================================================================================================================================== */
#pragma mark - Property Injection

- (void)injectPropertyDependenciesOn:(__autoreleasing id)instance withDefinition:(TyphoonDefinition*)definition
- (void)injectPropertyDependenciesOn:(id)instance withDefinition:(TyphoonDefinition*)definition
{
[self doBeforePropertyInjectionOn:instance withDefinition:definition];

Expand Down Expand Up @@ -279,7 +289,7 @@ - (BOOL)propertyIsCircular:(TyphoonAbstractInjectedProperty*)property onInstance
return [[instance circularDependentProperties] objectForKey:property.name] != nil;
}

- (void)injectCircularDependenciesOn:(__autoreleasing id <TyphoonIntrospectiveNSObject>)instance
- (void)injectCircularDependenciesOn:(id <TyphoonIntrospectiveNSObject>)instance
{
NSMutableDictionary* circularDependentProperties = [instance circularDependentProperties];
for (NSString* propertyName in [circularDependentProperties allKeys])
Expand Down Expand Up @@ -312,12 +322,40 @@ - (void)doAfterPropertyInjectionOn:(id <TyphoonIntrospectiveNSObject>)instance w
/* ====================================================================================================================================== */
#pragma mark - Private Methods

- (id)invokeInitializer:(TyphoonInitializer*)initializer on:(id)instanceOrClass
- (NSInvocation *) invocationToInitDefinition:(TyphoonDefinition *)definition
{
NSInvocation* invocation = [initializer asInvocationFor:instanceOrClass];
NSInvocation *invocation = nil;

if (definition.initializer) {
invocation = [self invocationForInitializer:definition.initializer withClass:definition.type];
} else {
invocation = [self defaultInitInvocation];
}

return invocation;
}

NSArray* injectedParameters = [initializer injectedParameters];
for (id <TyphoonInjectedParameter> parameter in injectedParameters)
- (NSInvocation *) defaultInitInvocation
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSObject instanceMethodSignatureForSelector:@selector(init)]];
[invocation setSelector:@selector(init)];
return invocation;
}

- (NSInvocation *) invocationForInitializer:(TyphoonInitializer *)initializer withClass:(Class)class
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[initializer methodSignatureForClass:class]];

[self configureInvocation:invocation forClass:class withParametersFromInitializer:initializer];

[invocation setSelector:initializer.selector];

return invocation;
}

- (void) configureInvocation:(NSInvocation *)invocation forClass:(Class)clazz withParametersFromInitializer:(TyphoonInitializer *)initializer
{
for (id <TyphoonInjectedParameter> parameter in [initializer injectedParameters])
{
if (parameter.type == TyphoonParameterInjectionTypeReference)
{
Expand All @@ -328,16 +366,17 @@ - (id)invokeInitializer:(TyphoonInitializer*)initializer on:(id)instanceOrClass
else if (parameter.type == TyphoonParameterInjectionTypeStringRepresentation)
{
TyphoonParameterInjectedWithStringRepresentation* byValue = (TyphoonParameterInjectedWithStringRepresentation*)parameter;
[self setArgumentFor:invocation index:byValue.index + 2 textValue:byValue.textValue
requiredType:[byValue resolveTypeWith:instanceOrClass]];
TyphoonTypeDescriptor *type = [byValue resolveTypeWith:clazz isClassMethod:initializer.isClassMethod];

[self setArgumentFor:invocation index:byValue.index + 2 textValue:byValue.textValue requiredType:type];
}
else if (parameter.type == TyphoonParameterInjectionTypeObjectInstance)
{
TyphoonParameterInjectedWithObjectInstance* byInstance = (TyphoonParameterInjectedWithObjectInstance*)parameter;
id value = byInstance.value;
BOOL isValuesIsWrapper = [value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSValue class]];

if (isValuesIsWrapper && [byInstance isPrimitiveParameterFor:instanceOrClass]) {
if (isValuesIsWrapper && [byInstance isPrimitiveParameterForClass:clazz isClassMethod:initializer.isClassMethod]) {
[self setPrimitiveArgumentForInvocation:invocation index:parameter.index + 2 fromValue:value];
} else {
[invocation setArgument:&value atIndex:parameter.index + 2];
Expand All @@ -350,12 +389,52 @@ - (id)invokeInitializer:(TyphoonInitializer*)initializer on:(id)instanceOrClass
[invocation setArgument:&collection atIndex:parameter.index + 2];
}
}
[invocation invoke];
__autoreleasing id <NSObject> returnValue = nil;
[invocation getReturnValue:&returnValue];
return returnValue;
}

//- (id)invokeInitializer:(TyphoonInitializer*)initializer on:(id)instanceOrClass UNAVAILABLE_ATTRIBUTE
//{
// NSInvocation* invocation = [initializer asInvocationFor:instanceOrClass];
//
// NSArray* injectedParameters = [initializer injectedParameters];
// for (id <TyphoonInjectedParameter> parameter in injectedParameters)
// {
// if (parameter.type == TyphoonParameterInjectionTypeReference)
// {
// TyphoonParameterInjectedByReference* byReference = (TyphoonParameterInjectedByReference*)parameter;
// id reference = [self componentForKey:byReference.reference];
// [invocation setArgument:&reference atIndex:parameter.index + 2];
// }
// else if (parameter.type == TyphoonParameterInjectionTypeStringRepresentation)
// {
// TyphoonParameterInjectedWithStringRepresentation* byValue = (TyphoonParameterInjectedWithStringRepresentation*)parameter;
// [self setArgumentFor:invocation index:byValue.index + 2 textValue:byValue.textValue
// requiredType:[byValue resolveTypeWith:instanceOrClass]];
// }
// else if (parameter.type == TyphoonParameterInjectionTypeObjectInstance)
// {
// TyphoonParameterInjectedWithObjectInstance* byInstance = (TyphoonParameterInjectedWithObjectInstance*)parameter;
// id value = byInstance.value;
// BOOL isValuesIsWrapper = [value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSValue class]];
//
// if (isValuesIsWrapper && [byInstance isPrimitiveParameterFor:instanceOrClass]) {
// [self setPrimitiveArgumentForInvocation:invocation index:parameter.index + 2 fromValue:value];
// } else {
// [invocation setArgument:&value atIndex:parameter.index + 2];
// }
// }
// else if (parameter.type == TyphoonParameterInjectionTypeAsCollection)
// {
// TyphoonParameterInjectedAsCollection* asCollection = (TyphoonParameterInjectedAsCollection*)parameter;
// id collection = [self buildCollectionWithValues:asCollection.values requiredType:asCollection.collectionType];
// [invocation setArgument:&collection atIndex:parameter.index + 2];
// }
// }
// [invocation invoke];
// __autoreleasing id <NSObject> returnValue = nil;
// [invocation getReturnValue:&returnValue];
// return returnValue;
//}

/* ====================================================================================================================================== */


Expand Down
Loading

0 comments on commit f32c6c1

Please sign in to comment.