Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit 9c7ee8e9f2ec90cd39b4c4a965eaa118fc73120b @farcaller committed
11 .gitignore
@@ -0,0 +1,11 @@
+# xcode noise
+build/*
+*.pbxuser
+*.mode1v3
+*.mode2v3
+
+# osx noise
+.DS_Store
+project.xcworkspace
+xcuserdata
+
273 Injective.xcodeproj/project.pbxproj
@@ -0,0 +1,273 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ A532BFFA14CB580A0034A43C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A532BFF914CB580A0034A43C /* Foundation.framework */; };
+ A532C00014CB580A0034A43C /* InjectiveContext.m in Sources */ = {isa = PBXBuildFile; fileRef = A532BFFF14CB580A0034A43C /* InjectiveContext.m */; };
+ A532C00814CB5A370034A43C /* NSObject+Injective.h in Headers */ = {isa = PBXBuildFile; fileRef = A532C00614CB5A370034A43C /* NSObject+Injective.h */; };
+ A532C00F14CB5C470034A43C /* InjectiveClassRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = A532C00D14CB5C470034A43C /* InjectiveClassRegistration.h */; };
+ A532C01014CB5C470034A43C /* InjectiveClassRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = A532C00E14CB5C470034A43C /* InjectiveClassRegistration.m */; };
+ A5F0CED914CC6D4A00B18B11 /* NSObject+Injective.m in Sources */ = {isa = PBXBuildFile; fileRef = A5F0CED814CC6D4A00B18B11 /* NSObject+Injective.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ A532BFF614CB580A0034A43C /* libInjective.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInjective.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ A532BFF914CB580A0034A43C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ A532BFFD14CB580A0034A43C /* Injective-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Injective-Prefix.pch"; sourceTree = "<group>"; };
+ A532BFFE14CB580A0034A43C /* InjectiveContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InjectiveContext.h; sourceTree = "<group>"; };
+ A532BFFF14CB580A0034A43C /* InjectiveContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InjectiveContext.m; sourceTree = "<group>"; };
+ A532C00614CB5A370034A43C /* NSObject+Injective.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+Injective.h"; sourceTree = "<group>"; };
+ A532C00D14CB5C470034A43C /* InjectiveClassRegistration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectiveClassRegistration.h; sourceTree = "<group>"; };
+ A532C00E14CB5C470034A43C /* InjectiveClassRegistration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InjectiveClassRegistration.m; sourceTree = "<group>"; };
+ A5F0CED814CC6D4A00B18B11 /* NSObject+Injective.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Injective.m"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ A532BFF314CB580A0034A43C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ A532BFFA14CB580A0034A43C /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ A532BFEB14CB580A0034A43C = {
+ isa = PBXGroup;
+ children = (
+ A532BFFB14CB580A0034A43C /* Injective */,
+ A532BFF814CB580A0034A43C /* Frameworks */,
+ A532BFF714CB580A0034A43C /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ A532BFF714CB580A0034A43C /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ A532BFF614CB580A0034A43C /* libInjective.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ A532BFF814CB580A0034A43C /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ A532BFF914CB580A0034A43C /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ A532BFFB14CB580A0034A43C /* Injective */ = {
+ isa = PBXGroup;
+ children = (
+ A532C00A14CB5BAE0034A43C /* Classes */,
+ A532BFFC14CB580A0034A43C /* Supporting Files */,
+ );
+ path = Injective;
+ sourceTree = "<group>";
+ };
+ A532BFFC14CB580A0034A43C /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ A532BFFD14CB580A0034A43C /* Injective-Prefix.pch */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ A532C00A14CB5BAE0034A43C /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ A532C00B14CB5BBE0034A43C /* Public */,
+ A532C00C14CB5C230034A43C /* Private */,
+ );
+ path = Classes;
+ sourceTree = "<group>";
+ };
+ A532C00B14CB5BBE0034A43C /* Public */ = {
+ isa = PBXGroup;
+ children = (
+ A532BFFE14CB580A0034A43C /* InjectiveContext.h */,
+ A532C00614CB5A370034A43C /* NSObject+Injective.h */,
+ );
+ path = Public;
+ sourceTree = "<group>";
+ };
+ A532C00C14CB5C230034A43C /* Private */ = {
+ isa = PBXGroup;
+ children = (
+ A532BFFF14CB580A0034A43C /* InjectiveContext.m */,
+ A5F0CED814CC6D4A00B18B11 /* NSObject+Injective.m */,
+ A532C00D14CB5C470034A43C /* InjectiveClassRegistration.h */,
+ A532C00E14CB5C470034A43C /* InjectiveClassRegistration.m */,
+ );
+ name = Private;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ A532BFF414CB580A0034A43C /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ A532C00814CB5A370034A43C /* NSObject+Injective.h in Headers */,
+ A532C00F14CB5C470034A43C /* InjectiveClassRegistration.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ A532BFF514CB580A0034A43C /* Injective */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = A532C00314CB580A0034A43C /* Build configuration list for PBXNativeTarget "Injective" */;
+ buildPhases = (
+ A532BFF214CB580A0034A43C /* Sources */,
+ A532BFF314CB580A0034A43C /* Frameworks */,
+ A532BFF414CB580A0034A43C /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Injective;
+ productName = Injective;
+ productReference = A532BFF614CB580A0034A43C /* libInjective.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ A532BFED14CB580A0034A43C /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0430;
+ ORGANIZATIONNAME = "Ciklum ApS";
+ };
+ buildConfigurationList = A532BFF014CB580A0034A43C /* Build configuration list for PBXProject "Injective" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = A532BFEB14CB580A0034A43C;
+ productRefGroup = A532BFF714CB580A0034A43C /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ A532BFF514CB580A0034A43C /* Injective */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ A532BFF214CB580A0034A43C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ A532C00014CB580A0034A43C /* InjectiveContext.m in Sources */,
+ A532C01014CB5C470034A43C /* InjectiveClassRegistration.m in Sources */,
+ A5F0CED914CC6D4A00B18B11 /* NSObject+Injective.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ A532C00114CB580A0034A43C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ A532C00214CB580A0034A43C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ COPY_PHASE_STRIP = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ A532C00414CB580A0034A43C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DSTROOT = /tmp/Injective.dst;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "Injective/Injective-Prefix.pch";
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Debug;
+ };
+ A532C00514CB580A0034A43C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DSTROOT = /tmp/Injective.dst;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "Injective/Injective-Prefix.pch";
+ OTHER_LDFLAGS = "-ObjC";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ A532BFF014CB580A0034A43C /* Build configuration list for PBXProject "Injective" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ A532C00114CB580A0034A43C /* Debug */,
+ A532C00214CB580A0034A43C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ A532C00314CB580A0034A43C /* Build configuration list for PBXNativeTarget "Injective" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ A532C00414CB580A0034A43C /* Debug */,
+ A532C00514CB580A0034A43C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = A532BFED14CB580A0034A43C /* Project object */;
+}
38 Injective/Classes/InjectiveClassRegistration.h
@@ -0,0 +1,38 @@
+//
+// InjectiveClassRegistration.h
+// Injective
+//
+// Created by Vladimir Pouzanov on 1/21/12.
+//
+// Copyright (c) 2012 Vladimir Pouzanov.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+#import "InjectiveContext.h"
+
+@interface InjectiveClassRegistration : NSObject
+
+@property (nonatomic, readonly) Class klass;
+@property (nonatomic, readonly) InjectiveContextInstantinationMode mode;
+@property (nonatomic, readwrite, retain) NSDictionary *registeredProperties;
+
++ (InjectiveClassRegistration *)registrationWithClass:(Class)klass instantinationMode:(InjectiveContextInstantinationMode)mode;
+
+@end
60 Injective/Classes/InjectiveClassRegistration.m
@@ -0,0 +1,60 @@
+//
+// InjectiveClassRegistration.m
+// Injective
+//
+// Created by Vladimir Pouzanov on 1/21/12.
+//
+// Copyright (c) 2012 Vladimir Pouzanov.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#import "InjectiveClassRegistration.h"
+
+@interface InjectiveClassRegistration ()
+
+- (InjectiveClassRegistration *)initWithClass:(Class)klass instantinationMode:(InjectiveContextInstantinationMode)mode;
+
+@end
+
+
+@implementation InjectiveClassRegistration
+
+@synthesize klass = _klass, mode = _mode, registeredProperties = _registeredProperties;
+
+- (InjectiveClassRegistration *)initWithClass:(Class)klass instantinationMode:(InjectiveContextInstantinationMode)mode
+{
+ if( (self = [super init]) ) {
+ _klass = klass;
+ _mode = mode;
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [_registeredProperties release];
+ [super dealloc];
+}
+
++ (InjectiveClassRegistration *)registrationWithClass:(Class)klass instantinationMode:(InjectiveContextInstantinationMode)mode
+{
+ return [[[self alloc] init] autorelease];
+}
+
+@end
203 Injective/Classes/InjectiveContext.m
@@ -0,0 +1,203 @@
+//
+// InjectiveContext.m
+// Injective
+//
+// Created by Vladimir Pouzanov on 1/21/12.
+//
+// Copyright (c) 2012 Vladimir Pouzanov.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#import "InjectiveContext.h"
+#import "InjectiveClassRegistration.h"
+#import <objc/runtime.h>
+
+@interface InjectiveContext ()
+
+- (id)createClassInstanceFromRegistration:(InjectiveClassRegistration *)reg withProperties:(NSDictionary *)props;
+- (NSDictionary *)createPropertiesMapForClass:(Class)klass;
+
+@end
+
+@implementation InjectiveContext
+{
+ NSMutableDictionary *_registeredClasses;
+ NSMutableDictionary *_registeredClassesSingletonInstances;
+ dispatch_queue_t _queue;
+}
+
++ (InjectiveContext *)defaultContext
+{
+ static dispatch_once_t onceToken;
+ static InjectiveContext *context;
+ dispatch_once(&onceToken, ^{
+ context = [[self alloc] init];
+ });
+ return context;
+}
+
+- (id)init
+{
+ if( (self = [super init]) ) {
+ _registeredClasses = [[NSMutableDictionary alloc] init];
+ _registeredClassesSingletonInstances = [[NSMutableDictionary alloc] init];
+ _queue = dispatch_queue_create([[NSString stringWithFormat:@"%@ Injective Queue", self] UTF8String], DISPATCH_QUEUE_SERIAL);
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [_registeredClasses release];
+ [_registeredClassesSingletonInstances release];
+ dispatch_release(_queue);
+ [super dealloc];
+}
+
+- (void)registerClass:(Class)klass instantinationMode:(InjectiveContextInstantinationMode)mode
+{
+ NSString *klassName = NSStringFromClass(klass);
+ dispatch_async(_queue, ^{
+ if([_registeredClasses objectForKey:klassName]) {
+ [NSException raise:NSInternalInconsistencyException format:@"Tired to register class %@ that is already registered in the injective context: %@", klass, self];
+ }
+ [_registeredClasses setObject:[InjectiveClassRegistration registrationWithClass:klass instantinationMode:mode] forKey:klassName];
+ });
+}
+
+- (id)instantinateClass:(Class)klass withProperties:(NSDictionary *)props
+{
+ __block InjectiveClassRegistration *reg = nil;
+ __block id instance = nil;
+ NSString *klassName = NSStringFromClass(klass);
+
+ dispatch_sync(_queue, ^{ reg = [_registeredClasses objectForKey:klassName]; });
+
+ if(reg) {
+ if(reg.mode == InjectiveContextInstantinationModeFactory) {
+ instance = [self createClassInstanceFromRegistration:reg withProperties:props];
+ } else {
+ instance = [_registeredClassesSingletonInstances objectForKey:klassName];
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ if(!instance) {
+ instance = [self createClassInstanceFromRegistration:reg withProperties:nil];
+ [_registeredClassesSingletonInstances setObject:instance forKey:klassName];
+ }
+ });
+ }
+ }
+ return instance;
+}
+
+#pragma mark -
+- (id)createClassInstanceFromRegistration:(InjectiveClassRegistration *)reg withProperties:(NSDictionary *)props
+{
+ Class klass = reg.klass;
+ id instance = [[[klass alloc] init] autorelease];
+
+ // check if the class requires pre-binding setup
+ if([klass respondsToSelector:@selector(injective_requredProperties)]) {
+ __block NSDictionary *registeredProperties;
+
+ // check if there is known property-class map and generate one if required
+ dispatch_sync(_queue, ^{
+ registeredProperties = reg.registeredProperties;
+ if(!registeredProperties) {
+ reg.registeredProperties = [self createPropertiesMapForClass:klass];
+ registeredProperties = reg.registeredProperties;
+ }
+ });
+
+ // iterate over the properties and set up connections via KVC
+ // TODO: this can cause deadlocks, that we must fix
+ // TODO: check for assign/weak properties? Look for [C]opy, [&]retain or W[eak]
+ [registeredProperties enumerateKeysAndObjectsUsingBlock:^(NSString *propName, NSString *propKlassName, BOOL *stop) {
+ Class propKlass = objc_getClass([propKlassName cStringUsingEncoding:NSASCIIStringEncoding]);
+ if(!propKlass) {
+ [NSException raise:NSInternalInconsistencyException format:@"Class %@ is not registered in the runtime, but is required for %@.%@", propKlassName,
+ NSStringFromClass(klass), propName];
+ }
+ id propInstance = [self instantinateClass:propKlass withProperties:nil];
+ if(!propInstance) {
+ [NSException raise:NSInternalInconsistencyException format:@"Injector %@ doesn't know how to instantinate %@", self, propKlassName];
+ }
+ [instance setValue:propInstance forKey:propName];
+ }];
+
+ // check if we have all the required properties on hand
+ NSMutableSet *registeredPropsSet = [NSMutableSet setWithArray:[registeredProperties allKeys]];
+ [registeredPropsSet addObjectsFromArray:[props allKeys]];
+ BOOL hasMissingProperties = [[klass injective_requredProperties] isSubsetOfSet:registeredPropsSet];
+ if(hasMissingProperties) {
+ [NSException raise:NSInternalInconsistencyException format:@"Class %@ instantinated with %@, but a set of %@ was requested.", NSStringFromClass(klass),
+ [klass injective_requredProperties], registeredPropsSet];
+ }
+ }
+
+ [instance setValuesForKeysWithDictionary:props];
+ return instance;
+}
+
+- (NSDictionary *)createPropertiesMapForClass:(Class)klass
+{
+ NSMutableDictionary *propsDict = [NSMutableDictionary dictionary];
+ NSSet *requiredProperties = [klass injective_requredProperties];
+ unsigned int outCount, i;
+ objc_property_t *properties = class_copyPropertyList(klass, &outCount);
+ for (i = 0; i < outCount; i++) {
+ objc_property_t property = properties[i];
+
+ const char *cPropName = property_getName(property);
+ NSString *propName = [NSString stringWithCString:cPropName encoding:NSASCIIStringEncoding];
+ // check if we really need this property
+ if([requiredProperties containsObject:propName]) {
+ const char *cPropAttrib = property_getAttributes(property);
+ // the attributes string is always at least 2 chars long, and the 2nd char must be @ for us to proceed
+ if(cPropAttrib[1] != '@') {
+ [NSException raise:NSInternalInconsistencyException format:@"Cannot map required property '%s' of class %@ as it does not "
+ @"point to object. Attributes: '%s'", cPropName, NSStringFromClass(klass), cPropAttrib];
+ }
+ // the attributes string must be at least 5 chars long: T@"<one char here>"
+ if(strlen(cPropAttrib) < 5) {
+ [NSException raise:NSInternalInconsistencyException format:@"Cannot map required property '%s' of class %@ as it does not "
+ @"contain enough chars to parse class name. Attributes: '%s'", cPropName, NSStringFromClass(klass), cPropAttrib];
+ }
+ cPropAttrib = cPropAttrib + 3;
+ // we don't support protocols yet
+ if(cPropAttrib[0] == '<') {
+ [NSException raise:NSInternalInconsistencyException format:@"Cannot map required property '%s' of class %@ as it "
+ @"maps to a Protocol, and we don't support them yet. Attributes: '%s'", cPropName, NSStringFromClass(klass), cPropAttrib];
+ }
+ char *cMappedKlassName = strdup(cPropAttrib);
+ char *cMappedKlassNameEnd = strchr(cMappedKlassName, '"');
+ if(cMappedKlassNameEnd == NULL) {
+ [NSException raise:NSInternalInconsistencyException format:@"Cannot map required property '%s' of class %@ as it does not "
+ @"contain the ending '\"'. Attributes: '%s'", cPropName, NSStringFromClass(klass), cPropAttrib];
+ }
+ cMappedKlassNameEnd = '\0';
+ NSString *mappedKlassName = [NSString stringWithCString:cMappedKlassName encoding:NSASCIIStringEncoding];
+ free(cMappedKlassName);
+
+ [propsDict setObject:mappedKlassName forKey:propName];
+ }
+ }
+ return [[propsDict copy] autorelease];
+}
+
+@end
42 Injective/Classes/NSObject+Injective.m
@@ -0,0 +1,42 @@
+//
+// NSObject+Injective.m
+// Injective
+//
+// Created by Vladimir Pouzanov on 1/21/12.
+//
+// Copyright (c) 2012 Vladimir Pouzanov.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+#import "InjectiveContext.h"
+
+@implementation NSObject (Injection)
+
++ (id)injectiveInstantiateWithProperties:(NSDictionary *)properties
+{
+ return [[InjectiveContext defaultContext] instantinateClass:self withProperties:properties];
+}
+
++ (id)injectiveInstantiate
+{
+ return [[InjectiveContext defaultContext] instantinateClass:self withProperties:nil];
+}
+
+@end
41 Injective/Classes/Public/InjectiveContext.h
@@ -0,0 +1,41 @@
+//
+// InjectiveContext.h
+// Injective
+//
+// Created by Vladimir Pouzanov on 1/21/12.
+//
+// Copyright (c) 2012 Vladimir Pouzanov.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+#import "NSObject+Injective.h"
+
+typedef enum InjectiveContextInstantinationMode {
+ InjectiveContextInstantinationModeFactory,
+ InjectiveContextInstantinationModeSingleton
+} InjectiveContextInstantinationMode;
+
+@interface InjectiveContext : NSObject
+
++ (InjectiveContext *)defaultContext;
+- (void)registerClass:(Class)klass instantinationMode:(InjectiveContextInstantinationMode)mode;
+- (id)instantinateClass:(Class)klass withProperties:(NSDictionary *)props;
+
+@end
73 Injective/Classes/Public/NSObject+Injective.h
@@ -0,0 +1,73 @@
+//
+// NSObject+Injective.h
+// Injective
+//
+// Created by Vladimir Pouzanov on 1/21/12.
+//
+// Copyright (c) 2012 Vladimir Pouzanov.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#import <Foundation/Foundation.h>
+
+@interface NSObject (InjectiveProtocol)
+
+/** An array of properties, that must be set for object to come alive
+ *
+ * The properties are filled in from Injection registered classes and from local context of
+ * +injectionInstantinateWithProperties:
+ */
++ (NSSet *)injective_requredProperties;
+
+@end
+
+@interface NSObject (Injective)
+
+/** Create a new instance of the receiving class or get a singleton
+ */
++ (id)injectiveInstantiateWithProperties:(NSDictionary *)properties;
++ (id)injectiveInstantiate;
+
+@end
+
+#define injective_register(klass, ...) \
+ + (void)initialize \
+ { \
+ if(self == [klass class]) { \
+ [[InjectiveContext defaultContext] registerClass:[klass class] instantinationMode:InjectiveContextInstantinationModeFactory]; \
+ } \
+ } \
+ \
+ + (NSSet *)injective_requredProperties \
+ { \
+ return [NSSet setWithObjects:__VA_ARGS__, nil]; \
+ }
+
+#define injective_register_singleton(klass, ...) \
+ + (void)initialize \
+ { \
+ if(self == [klass class]) { \
+ [[InjectiveContext defaultContext] registerClass:[klass class] instantinationMode:InjectiveContextInstantinationModeSingleton]; \
+ } \
+ } \
+ \
+ + (NSSet *)injective_requredProperties \
+ { \
+ return [NSSet setWithObjects:__VA_ARGS__, nil]; \
+ }
7 Injective/Injective-Prefix.pch
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'Injective' target in the 'Injective' project
+//
+
+#ifdef __OBJC__
+ #import <Foundation/Foundation.h>
+#endif

0 comments on commit 9c7ee8e

Please sign in to comment.
Something went wrong with that request. Please try again.