Permalink
Browse files

keeping global context reference since initialize method on class is …

…called lazily
  • Loading branch information...
1 parent 3727f58 commit 9a645176a4b1318ad6543b184c3f8ea13c1d27f0 @dewind dewind committed Dec 7, 2010
View
8 Headers/Objection.h
@@ -7,15 +7,15 @@
#define objection_register(value) \
+ (void)initialize { \
- if (self == NSClassFromString(value)) { \
- [Objection registerClass:NSClassFromString(value) lifeCycle: ObjectionInstantiationRule_Everytime]; \
+ if (self == [value class]) { \
+ [Objection registerClass:[value class] lifeCycle: ObjectionInstantiationRule_Everytime]; \
} \
}
#define objection_register_singleton(value) \
+ (void)initialize { \
- if (self == NSClassFromString(value)) { \
- [Objection registerClass:NSClassFromString(value) lifeCycle: ObjectionInstantiationRule_Singleton]; \
+ if (self == [value class]) { \
+ [Objection registerClass:[value class] lifeCycle: ObjectionInstantiationRule_Singleton]; \
} \
}
View
1 Headers/ObjectionInjector.h
@@ -1,6 +1,7 @@
#import <Foundation/Foundation.h>
@interface ObjectionInjector : NSObject {
+ NSDictionary *_globalContext;
NSMutableDictionary *_context;
}
View
10 Source/Objection.m
@@ -13,7 +13,13 @@ + (ObjectionInjector *) createInjector:(ObjectionModule *)aModule {
}
+ (ObjectionInjector *) createInjector {
- return [[[ObjectionInjector alloc] initWithContext:gObjectionContext] autorelease];
+ pthread_mutex_lock(&gObjectionMutex);
+ @try {
+ return [[[ObjectionInjector alloc] initWithContext:gObjectionContext] autorelease];
+ }
+ @finally {
+ pthread_mutex_unlock(&gObjectionMutex);
+ }
}
+ (void)initialize {
@@ -29,13 +35,15 @@ + (void)initialize {
+ (void) registerClass:(Class)theClass lifeCycle:(ObjectionInstantiationRule)lifeCycle {
pthread_mutex_lock(&gObjectionMutex);
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (lifeCycle != ObjectionInstantiationRule_Singleton && lifeCycle != ObjectionInstantiationRule_Everytime) {
@throw [NSException exceptionWithName:@"ObjectionInjectorException" reason:@"Invalid Instantiation Rule" userInfo:nil];
}
if (theClass && [gObjectionContext objectForKey:NSStringFromClass(theClass)] == nil) {
[gObjectionContext setObject:[ObjectionEntry withClass:theClass lifeCycle:lifeCycle] forKey:NSStringFromClass(theClass)];
}
+ [pool drain];
pthread_mutex_unlock(&gObjectionMutex);
}
View
126 Source/ObjectionEntry.m
@@ -1,34 +1,12 @@
#import "ObjectionEntry.h"
-#import <objc/runtime.h>
-
-static Class ParseClassFromProperty(objc_property_t property) {
- NSString *attributes = [NSString stringWithCString: property_getAttributes(property) encoding: NSASCIIStringEncoding];
- NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding];
+#import "Objection.h"
- NSRange startRange = [attributes rangeOfString:@"T@\""];
- if (startRange.location == NSNotFound) {
- @throw [NSException exceptionWithName:@"ObjectionInjectionException" reason:[NSString stringWithFormat:@"Unable to determine class type for property declaration: '%@'", propertyName] userInfo:nil];
- }
-
- NSString *startOfClassName = [attributes substringFromIndex:startRange.length];
- NSRange endRange = [startOfClassName rangeOfString:@"\""];
-
- if (endRange.location == NSNotFound) {
- @throw [NSException exceptionWithName:@"ObjectionInjectionException" reason:[NSString stringWithFormat:@"Unable to determine class type for property declaration: '%@'", propertyName] userInfo:nil];
- }
-
- NSString *className = [startOfClassName substringToIndex:endRange.location];
- Class theClass = NSClassFromString(className);
-
- if(!theClass) {
- @throw [NSException exceptionWithName:@"ObjectionInjectionException" reason:[NSString stringWithFormat:@"Unable get class for name '%@' for property '%@'", className, propertyName] userInfo:nil];
- }
-
- return theClass;
-}
+#import <objc/runtime.h>
@interface ObjectionEntry (Private)
- (void) notifyObjectThatItIsReady: (id)object;
+- (Class) parseClassFromProperty:(objc_property_t)property;
+- (id) buildObject;
@end
@@ -50,6 +28,37 @@ - (id)initWithClass:(Class)theClass lifeCycle:(ObjectionInstantiationRule)theLif
return self;
}
+- (id) extractObject {
+ if (self.lifeCycle == ObjectionInstantiationRule_Everytime) {
+ return [self buildObject];
+ } else if (!_storageCache) {
+ _storageCache = [self buildObject];
+ }
+
+ return _storageCache;
+}
+
+- (void)dealloc {
+ [_storageCache release]; _storageCache = nil;
+ [super dealloc];
+}
+
+#pragma mark NSCopying
+#pragma mark -
+
+- (id)copyWithZone:(NSZone *)zone {
+ return [[ObjectionEntry alloc] initWithClass:self.classEntry lifeCycle:self.lifeCycle];
+}
+
+#pragma mark Private Methods
+#pragma mark -
+
+- (void) notifyObjectThatItIsReady: (id) object {
+ if([object respondsToSelector:@selector(awakeFromObjection)]) {
+ [object performSelector:@selector(awakeFromObjection)];
+ }
+}
+
- (id)buildObject {
if([self.classEntry respondsToSelector:@selector(objectionRequires)]) {
NSArray *properties = [self.classEntry performSelector:@selector(objectionRequires)];
@@ -62,12 +71,12 @@ - (id)buildObject {
@throw [NSException exceptionWithName:@"ObjectionInjectionException" reason:[NSString stringWithFormat:@"Unable to find property declaration: '%@'", propertyName] userInfo:nil];
}
- Class desiredClass = ParseClassFromProperty(property);
- id theObject = [_injector performSelector:@selector(getObject:) withObject:desiredClass];
+ Class desiredClass = [self parseClassFromProperty:property];
+ id theObject = [_injector getObject:desiredClass];
- // Insantiate it using a default constructor
if(!theObject) {
- theObject = [[[desiredClass alloc] init] autorelease];
+ [Objection registerClass:desiredClass lifeCycle: ObjectionInstantiationRule_Everytime];
+ theObject = [_injector getObject:desiredClass];
}
[propertiesDictionary setObject:theObject forKey:propertyName];
@@ -76,7 +85,6 @@ - (id)buildObject {
[objectUnderConstruction setValuesForKeysWithDictionary:propertiesDictionary];
[self notifyObjectThatItIsReady: objectUnderConstruction];
-
return objectUnderConstruction;
} else {
@@ -87,42 +95,38 @@ - (id)buildObject {
}
-- (id) extractObject {
- if (self.lifeCycle == ObjectionInstantiationRule_Everytime) {
- return [self buildObject];
- } else if (!_storageCache) {
- _storageCache = [self buildObject];
- }
-
- return _storageCache;
-}
-
-- (void)dealloc {
- [_storageCache release]; _storageCache = nil;
- [super dealloc];
-}
-
-#pragma mark NSCopying
+#pragma mark Class Methods
#pragma mark -
-- (id)copyWithZone:(NSZone *)zone {
- return [[ObjectionEntry alloc] initWithClass:self.classEntry lifeCycle:self.lifeCycle];
++ (id)withClass:(Class)theClass lifeCycle:(ObjectionInstantiationRule)theLifeCycle {
+ return [[[ObjectionEntry alloc] initWithClass:theClass lifeCycle:theLifeCycle] autorelease];
}
#pragma mark Private Methods
-#pragma mark -
-- (void) notifyObjectThatItIsReady: (id) object {
- if([object respondsToSelector:@selector(awakeFromObjection)]) {
- [object performSelector:@selector(awakeFromObjection)];
+- (Class)parseClassFromProperty:(objc_property_t)property {
+ NSString *attributes = [NSString stringWithCString: property_getAttributes(property) encoding: NSASCIIStringEncoding];
+ NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding];
+
+ NSRange startRange = [attributes rangeOfString:@"T@\""];
+ if (startRange.location == NSNotFound) {
+ @throw [NSException exceptionWithName:@"ObjectionInjectionException" reason:[NSString stringWithFormat:@"Unable to determine class type for property declaration: '%@'", propertyName] userInfo:nil];
}
+
+ NSString *startOfClassName = [attributes substringFromIndex:startRange.length];
+ NSRange endRange = [startOfClassName rangeOfString:@"\""];
+
+ if (endRange.location == NSNotFound) {
+ @throw [NSException exceptionWithName:@"ObjectionInjectionException" reason:[NSString stringWithFormat:@"Unable to determine class type for property declaration: '%@'", propertyName] userInfo:nil];
+ }
+
+ NSString *className = [startOfClassName substringToIndex:endRange.location];
+ Class theClass = NSClassFromString(className);
+
+ if(!theClass) {
+ @throw [NSException exceptionWithName:@"ObjectionInjectionException" reason:[NSString stringWithFormat:@"Unable get class for name '%@' for property '%@'", className, propertyName] userInfo:nil];
+ }
+
+ return theClass;
}
-
-#pragma mark Class Methods
-#pragma mark -
-
-+ (id)withClass:(Class)theClass lifeCycle:(ObjectionInstantiationRule)theLifeCycle {
- return [[[ObjectionEntry alloc] initWithClass:theClass lifeCycle:theLifeCycle] autorelease];
-}
-
@end
View
33 Source/ObjectionInjector.m
@@ -10,34 +10,37 @@ - (void)configureContext;
@implementation ObjectionInjector
- (id)initWithContext:(NSDictionary *)initialContext {
if ((self = [super init])) {
- _context = [[NSMutableDictionary alloc] initWithDictionary:initialContext copyItems:YES];
- [self configureContext];
+ _globalContext = [initialContext retain];
+ _context = [[NSMutableDictionary alloc] init];
}
return self;
}
- (id)getObject:(Class)theClass {
NSString *key = NSStringFromClass(theClass);
- ObjectionEntry *entry = [_context objectForKey:key];
- if (theClass && entry) {
- return [entry extractObject];
+ ObjectionEntry *injectorEntry = [_context objectForKey:key];
+
+ if (!injectorEntry) {
+ ObjectionEntry *entry = [_globalContext objectForKey:key];
+ if (entry) {
+ injectorEntry = [entry copy];
+ injectorEntry.injector = self;
+ [_context setObject:injectorEntry forKey:key];
+ }
+ }
+
+ if (theClass && injectorEntry) {
+ return [injectorEntry extractObject];
}
+
return nil;
}
- (void)dealloc {
- [_context release]; _context = nil;
+ [_globalContext release]; _globalContext = nil;
+ [_context release]; _context = nil;
[super dealloc];
}
-#pragma mark Private
-#pragma mark -
-
-- (void)configureContext {
- for (NSString *key in _context) {
- ObjectionEntry *entry = [_context objectForKey:key];
- entry.injector = self;
- }
-}
@end
View
6 Specs/BasicUsageSpecs.m
@@ -48,6 +48,12 @@
assertThat(carFactory1, is(sameInstance(carFactory2)));
});
+it(@"will not return the same instance per injector if object is a singleton", ^{
+ id carFactory1 = [[Objection globalInjector] getObject:[CarFactory class]];
+ id carFactory2 = [[Objection createInjector] getObject:[CarFactory class]];
+ assertThat(carFactory1, isNot(sameInstance(carFactory2)));
+});
+
it(@"returns nil if the class is nil", ^{
assertThat([[Objection globalInjector] getObject:nil], is(nilValue()));
});
View
6 Specs/Fixtures.m
@@ -2,7 +2,7 @@
#import "Objection.h"
@implementation Engine
-objection_register(@"Engine")
+objection_register(Engine)
@synthesize awake;
- (void) awakeFromObjection {
@@ -16,7 +16,7 @@ @implementation Brakes
@implementation Car
-objection_register(@"Car")
+objection_register(Car)
@synthesize engine, brakes, awake;
@@ -28,5 +28,5 @@ - (void)awakeFromObjection {
@end
@implementation CarFactory
-objection_register_singleton(@"CarFactory")
+objection_register_singleton(CarFactory)
@end
View
36 Specs/InheritanceSpecs.m
@@ -9,7 +9,7 @@ @interface Person : NSObject
@end
@implementation Person
-objection_register(@"Person")
+objection_register(Person)
objection_requires(@"attributes")
@synthesize attributes=_attributes;
@end
@@ -22,7 +22,7 @@ @interface Programmer : Person
@end
@implementation Programmer
-objection_register(@"Programmer")
+objection_register(Programmer)
objection_requires(@"favoriteLanguages")
@synthesize favoriteLanguages=_favoriteLanguages;
@@ -38,7 +38,7 @@ @interface NoInheritance : NSObject
@end
@implementation NoInheritance
-objection_register(@"NoInheritence")
+objection_register(NoInheritance)
objection_requires(@"something")
@synthesize something=_something;
@@ -47,19 +47,19 @@ @implementation NoInheritance
SPEC_BEGIN(InheritanceSpecs)
-// beforeEach(^{
-// ObjectionInjector *injector = [Objection createInjector];
-// [Objection setGlobalInjector:injector];
-// });
-//
-// it(@"coalesces dependencies from parent to child", ^{
-// Programmer *programmer = [[Objection globalInjector] getObject:[Programmer class]];
-// assertThat(programmer.attributes, is(notNilValue()));
-// assertThat(programmer.favoriteLanguages, is(notNilValue()));
-// });
-//
-// it(@"does not throw a fit if the base class does not implement super", ^{
-// NoInheritance *noParentObjectWithRequires = [[Objection globalInjector] getObject:[NoInheritance class]];
-// assertThat(noParentObjectWithRequires.something, is(notNilValue()));
-// });
+ beforeEach(^{
+ ObjectionInjector *injector = [Objection createInjector];
+ [Objection setGlobalInjector:injector];
+ });
+
+ it(@"coalesces dependencies from parent to child", ^{
+ Programmer *programmer = [[Objection globalInjector] getObject:[Programmer class]];
+ assertThat(programmer.attributes, is(notNilValue()));
+ assertThat(programmer.favoriteLanguages, is(notNilValue()));
+ });
+
+ it(@"does not throw a fit if the base class does not implement super", ^{
+ NoInheritance *noParentObjectWithRequires = [[Objection globalInjector] getObject:[NoInheritance class]];
+ assertThat(noParentObjectWithRequires.something, is(notNilValue()));
+ });
SPEC_END
View
6 Specs/InjectionErrorFixtures.m
@@ -2,20 +2,20 @@
#import "Objection.h"
@implementation UnsupportedPropertyObject
-objection_register(@"UnsupportedPropertyObject")
+objection_register(UnsupportedPropertyObject)
objection_requires(@"myInteger")
@synthesize myInteger;
@end
@implementation BadPropertyObject
@synthesize someObject;
-objection_register(@"BadPropertyObject")
+objection_register(BadPropertyObject)
objection_requires(@"badProperty")
@end
@implementation ReadOnlyPropertyObject
-objection_register(@"ReadOnlyPropertyObject")
+objection_register(ReadOnlyPropertyObject)
objection_requires(@"someObject")
@synthesize someObject=_someObject;
View
64 Specs/InjectionErrorsSpecs.m
@@ -8,37 +8,37 @@
ObjectionInjector *injector = [Objection createInjector];
[Objection setGlobalInjector:injector];
});
-//
-//it(@"throws an exception if property type if not an object", ^{
-// @try {
-// [[Objection globalInjector] getObject:[UnsupportedPropertyObject class]];
-// fail(@"Should have thrown an exception");
-// }
-// @catch (NSException * e) {
-// assertThat([e reason], is(@"Unable to determine class type for property declaration: 'myInteger'"));
-// }
-//});
-//
-//it(@"throws an exception if property cannot be found", ^{
-// @try {
-// [[Objection globalInjector] getObject:[BadPropertyObject class]];
-// fail(@"Should have thrown an exception");
-// }
-// @catch (NSException * e) {
-// assertThat([e reason], is(@"Unable to find property declaration: 'badProperty'"));
-// }
-//
-//});
-//
-//it(@"throws if instantiation rule if not valid", ^{
-// @try {
-// [Objection registerClass:[CarFactory class] lifeCycle:3];
-// fail(@"Should have thrown an exception");
-// }
-// @catch (NSException * e) {
-// assertThat([e reason], is(@"Invalid Instantiation Rule"));
-// }
-//});
-//
+
+it(@"throws an exception if property type if not an object", ^{
+ @try {
+ [[Objection globalInjector] getObject:[UnsupportedPropertyObject class]];
+ fail(@"Should have thrown an exception");
+ }
+ @catch (NSException * e) {
+ assertThat([e reason], is(@"Unable to determine class type for property declaration: 'myInteger'"));
+ }
+});
+
+it(@"throws an exception if property cannot be found", ^{
+ @try {
+ [[Objection globalInjector] getObject:[BadPropertyObject class]];
+ fail(@"Should have thrown an exception");
+ }
+ @catch (NSException * e) {
+ assertThat([e reason], is(@"Unable to find property declaration: 'badProperty'"));
+ }
+
+});
+
+it(@"throws if instantiation rule if not valid", ^{
+ @try {
+ [Objection registerClass:[CarFactory class] lifeCycle:3];
+ fail(@"Should have thrown an exception");
+ }
+ @catch (NSException * e) {
+ assertThat([e reason], is(@"Invalid Instantiation Rule"));
+ }
+});
+
SPEC_END

0 comments on commit 9a64517

Please sign in to comment.