Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Made CouchModel properties more efficient

Now using Objective-C runtime imp_implementationWithBlock function to avoid the overhead of computing
the property name from the method selector on every call. Should make property access a lot faster!
  • Loading branch information...
commit cb2c13247799002234952234f2e6e8dbfea00f63 1 parent 205ed25
@snej snej authored
View
4 CouchCocoa.xcodeproj/project.pbxproj
@@ -1125,7 +1125,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
- CURRENT_PROJECT_VERSION = 10;
+ CURRENT_PROJECT_VERSION = 11;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@@ -1148,7 +1148,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
- CURRENT_PROJECT_VERSION = 10;
+ CURRENT_PROJECT_VERSION = 11;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Couch/CouchPrefix.pch;
View
8 Model/CouchDynamicObject.h
@@ -41,9 +41,9 @@
// ADVANCED STUFF FOR SUBCLASSES TO OVERRIDE:
-+ (IMP) impForGetterOfClass: (Class)propertyClass;
-+ (IMP) impForSetterOfClass: (Class)propertyClass;
-+ (IMP) impForGetterOfType: (const char*)propertyType;
-+ (IMP) impForSetterOfType: (const char*)propertyType;
++ (IMP) impForGetterOfProperty: (NSString*)property ofClass: (Class)propertyClass;
++ (IMP) impForSetterOfProperty: (NSString*)property ofClass: (Class)propertyClass;
++ (IMP) impForGetterOfProperty: (NSString*)property ofType: (const char*)propertyType;
++ (IMP) impForSetterOfProperty: (NSString*)property ofType: (const char*)propertyType;
@end
View
87 Model/CouchDynamicObject.m
@@ -1,5 +1,5 @@
//
-// CouchDictObject.m
+// CouchDynamicObject.m
// CouchCocoa
//
// Created by Jens Alfke on 8/6/09.
@@ -11,6 +11,13 @@
#import <objc/runtime.h>
+#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
+#define USE_BLOCKS (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)
+#else
+#define USE_BLOCKS (MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
+#endif
+
+
@implementation CouchDynamicObject
@@ -67,6 +74,15 @@ + (NSString*) setterKey: (SEL)sel {return setterKey(sel);}
#pragma mark - GENERIC ACCESSOR METHOD IMPS:
+#if USE_BLOCKS
+
+static inline void setIdProperty(CouchDynamicObject *self, NSString* property, id value) {
+ BOOL result = [self setValue: value ofProperty: property];
+ NSCAssert(result, @"Property %@.%@ is not settable", [self class], property);
+}
+
+#else
+
static id getIdProperty(CouchDynamicObject *self, SEL _cmd) {
return [self getValueOfProperty: getterKey(_cmd)];
}
@@ -102,6 +118,8 @@ static void setDoubleProperty(CouchDynamicObject *self, SEL _cmd, double value)
setIdProperty(self, _cmd, [NSNumber numberWithDouble:value]);
}
+#endif // USE_BLOCKS
+
#pragma mark - PROPERTY INTROSPECTION:
@@ -213,52 +231,97 @@ + (Class) classOfProperty: (NSString*)propertyName {
}
-// IDEA: Would be awesome to use imp_implementationWithBlock() on OS X 10.7+ and iOS 4.3+.
-
-
-+ (IMP) impForGetterOfClass: (Class)propertyClass {
++ (IMP) impForGetterOfProperty: (NSString*)property ofClass: (Class)propertyClass {
+#if USE_BLOCKS
+ return imp_implementationWithBlock(^id(CouchDynamicObject* receiver) {
+ return [receiver getValueOfProperty: property];
+ });
+#else
return (IMP)getIdProperty;
+#endif
}
-+ (IMP) impForSetterOfClass: (Class)propertyClass {
++ (IMP) impForSetterOfProperty: (NSString*)property ofClass: (Class)propertyClass {
+#if USE_BLOCKS
+ return imp_implementationWithBlock(^(CouchDynamicObject* receiver, id value) {
+ setIdProperty(receiver, property, value);
+ });
+#else
return (IMP)setIdProperty;
+#endif
}
-+ (IMP) impForGetterOfType: (const char*)propertyType {
++ (IMP) impForGetterOfProperty: (NSString*)property ofType: (const char*)propertyType {
switch (propertyType[0]) {
case _C_ID:
- return [self impForGetterOfClass: classFromType(propertyType)];
+ return [self impForGetterOfProperty: property ofClass: classFromType(propertyType)];
case _C_INT:
case _C_SHT:
case _C_USHT:
case _C_CHR:
case _C_UCHR:
+#if USE_BLOCKS
+ return imp_implementationWithBlock(^int(CouchDynamicObject* receiver) {
+ return [[receiver getValueOfProperty: property] intValue];
+ });
+#else
return (IMP)getIntProperty;
+#endif
case _C_BOOL:
+#if USE_BLOCKS
+ return imp_implementationWithBlock(^bool(CouchDynamicObject* receiver) {
+ return [[receiver getValueOfProperty: property] boolValue];
+ });
+#else
return (IMP)getBoolProperty;
+#endif
case _C_DBL:
+#if USE_BLOCKS
+ return imp_implementationWithBlock(^double(CouchDynamicObject* receiver) {
+ return [[receiver getValueOfProperty: property] doubleValue];
+ });
+#else
return (IMP)getDoubleProperty;
+#endif
default:
// TODO: handle more scalar property types.
return NULL;
}
}
-+ (IMP) impForSetterOfType: (const char*)propertyType {
++ (IMP) impForSetterOfProperty: (NSString*)property ofType: (const char*)propertyType {
switch (propertyType[0]) {
case _C_ID:
- return [self impForSetterOfClass: classFromType(propertyType)];
+ return [self impForSetterOfProperty: property ofClass: classFromType(propertyType)];
case _C_INT:
case _C_SHT:
case _C_USHT:
case _C_CHR: // Note that "BOOL" is a typedef so it compiles to 'char'
case _C_UCHR:
+#if USE_BLOCKS
+ return imp_implementationWithBlock(^(CouchDynamicObject* receiver, int value) {
+ setIdProperty(receiver, property, [NSNumber numberWithInt: value]);
+ });
+#else
return (IMP)setIntProperty;
+#endif
case _C_BOOL: // This is the true native C99/C++ "bool" type
+#if USE_BLOCKS
+ return imp_implementationWithBlock(^(CouchDynamicObject* receiver, bool value) {
+ setIdProperty(receiver, property, [NSNumber numberWithBool: value]);
+ });
+#else
return (IMP)setBoolProperty;
+#endif
case _C_DBL:
+#if USE_BLOCKS
+ return imp_implementationWithBlock(^(CouchDynamicObject* receiver, double value) {
+ setIdProperty(receiver, property, [NSNumber numberWithDouble: value]);
+ });
+#else
return (IMP)setDoubleProperty;
+#endif
default:
// TODO: handle more scalar property types.
return NULL;
@@ -282,7 +345,7 @@ + (BOOL)resolveInstanceMethod:(SEL)sel {
if (getPropertyInfo(self, key, YES, &declaredInClass, &propertyType)) {
strcpy(signature, "v@: ");
signature[3] = propertyType[0];
- accessor = [self impForSetterOfType: propertyType];
+ accessor = [self impForSetterOfProperty: key ofType: propertyType];
}
} else if (isGetter(name)) {
// choose an appropriately typed getter function.
@@ -290,7 +353,7 @@ + (BOOL)resolveInstanceMethod:(SEL)sel {
if (getPropertyInfo(self, key, NO, &declaredInClass, &propertyType)) {
strcpy(signature, " @:");
signature[0] = propertyType[0];
- accessor = [self impForGetterOfType: propertyType];
+ accessor = [self impForGetterOfProperty: key ofType: propertyType];
}
} else {
// Not a getter or setter name.
View
59 Model/CouchModel.m
@@ -9,6 +9,7 @@
#import "CouchModel.h"
#import "CouchModelFactory.h"
#import "CouchInternal.h"
+#import <objc/runtime.h>
@interface CouchModel ()
@@ -419,47 +420,37 @@ - (void) setModel: (CouchModel*)model forProperty: (NSString*)property {
[self setValue: docID ofProperty: property];
}
-NS_INLINE NSString *getterKey(SEL sel) {
- return [NSString stringWithUTF8String:sel_getName(sel)];
-}
-
-static id getDataProperty(CouchModel *self, SEL _cmd) {
- return [self getDataProperty: getterKey(_cmd)];
-}
-
-static id getDateProperty(CouchModel *self, SEL _cmd) {
- return [self getDateProperty: getterKey(_cmd)];
-}
-
-static id getModelProperty(CouchModel *self, SEL _cmd) {
- return [self getModelProperty: getterKey(_cmd)];
-}
-static void setModelProperty(CouchModel *self, SEL _cmd, id value) {
- return [self setModel: value forProperty: [CouchDynamicObject setterKey: _cmd]];
-}
-
-
-+ (IMP) impForGetterOfClass: (Class)propertyClass {
++ (IMP) impForGetterOfProperty: (NSString*)property ofClass: (Class)propertyClass {
if (propertyClass == Nil || propertyClass == [NSString class]
|| propertyClass == [NSNumber class] || propertyClass == [NSArray class]
|| propertyClass == [NSDictionary class])
- return [super impForGetterOfClass: propertyClass]; // Basic classes (including 'id')
- else if (propertyClass == [NSData class])
- return (IMP)getDataProperty;
- else if (propertyClass == [NSDate class])
- return (IMP)getDateProperty;
- else if ([propertyClass isSubclassOfClass: [CouchModel class]])
- return (IMP)getModelProperty;
- else
+ return [super impForGetterOfProperty: property ofClass: propertyClass]; // Basic classes (including 'id')
+ else if (propertyClass == [NSData class]) {
+ return imp_implementationWithBlock(^id(CouchModel* receiver) {
+ return [receiver getDataProperty: property];
+ });
+ } else if (propertyClass == [NSDate class]) {
+ return imp_implementationWithBlock(^id(CouchModel* receiver) {
+ return [receiver getDateProperty: property];
+ });
+ } else if ([propertyClass isSubclassOfClass: [CouchModel class]]) {
+ return imp_implementationWithBlock(^id(CouchModel* receiver) {
+ return [receiver getModelProperty: property];
+ });
+ } else {
return NULL; // Unsupported
+ }
}
-+ (IMP) impForSetterOfClass: (Class)propertyClass {
- if ([propertyClass isSubclassOfClass: [CouchModel class]])
- return (IMP)setModelProperty;
- else
- return [super impForSetterOfClass: propertyClass];
++ (IMP) impForSetterOfProperty: (NSString*)property ofClass: (Class)propertyClass {
+ if ([propertyClass isSubclassOfClass: [CouchModel class]]) {
+ return imp_implementationWithBlock(^(CouchModel* receiver, CouchModel* value) {
+ [receiver setModel: value forProperty: property];
+ });
+ } else {
+ return [super impForSetterOfProperty: property ofClass: propertyClass];
+ }
}
Please sign in to comment.
Something went wrong with that request. Please try again.