Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

class method swizzle implementation & method aliasing #1

Merged
2 commits merged into from

2 participants

@outis

There are two changes here. The first implements class method swizzling in a very simple manner (call your instance method swizzling method on the meta-class). The second adds new functionality: instance & class method aliasing. This is perhaps outside the scope of JRSwizzle, but not too far outside. At the very least, it's closely related. At its best, it broadens the scope of JRSwizzle to method manipulation. Is aliasing an appropriate addition for JRSwizzle?

@rentzsch
Owner

Pulled, thanks!

I'm unsure if aliasing is a good thing to have in JRSwizzle. What are you using it for?

@outis

It's used in another project, adding support for the KVC operators to NSDictionary, though it's not essential. Another option is a fork focused on method manipulation, with yet more operations. Maybe an aspect-oriented programming library.

@rentzsch
Owner

Ah, yeah I would say it shouldn't be in JRSwizzle then. I'll pull it out when I take my next whack at the project.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 25, 2011
  1. @outis

    [DEV] added method aliasing

    outis authored
  2. @outis
This page is out of date. Refresh to see the latest.
Showing with 58 additions and 4 deletions.
  1. +6 −0 JRSwizzle.h
  2. +52 −4 JRSwizzle.m
View
6 JRSwizzle.h
@@ -10,4 +10,10 @@
@interface NSObject (JRSwizzle)
+ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_;
+ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_;
+
++ (BOOL)jr_aliasMethod:(SEL)methSel_ withName:(const char*)aliasName_ error:(NSError**)error_;
++ (BOOL)jr_aliasMethod:(SEL)methSel_ withSelector:(SEL)aliasSel_ error:(NSError**)error_;
+
++ (BOOL)jr_aliasClassMethod:(SEL)methSel_ withName:(const char*)aliasName_ error:(NSError**)error_;
++ (BOOL)jr_aliasClassMethod:(SEL)methSel_ withSelector:(SEL)aliasSel_ error:(NSError**)error_;
@end
View
56 JRSwizzle.m
@@ -8,13 +8,14 @@
#import "JRSwizzle.h"
#import <objc/objc-class.h>
-#define SetNSError(ERROR_VAR, FORMAT,...) \
+#define SetNSErrorFor(FUNC, ERROR_VAR, FORMAT,...) \
if (ERROR_VAR) { \
- NSString *errStr = [@"+[NSObject(JRSwizzle) jr_swizzleMethod:withMethod:error:]: " stringByAppendingFormat:FORMAT,##__VA_ARGS__]; \
+ NSString *errStr = [NSString stringWithFormat:@"%s: " FORMAT,FUNC,##__VA_ARGS__]; \
*ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \
code:-1 \
userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \
}
+#define SetNSError(ERROR_VAR, FORMAT,...) SetNSErrorFor(__func__, ERROR_VAR, FORMAT, ##__VA_ARGS__)
@implementation NSObject (JRSwizzle)
@@ -109,8 +110,55 @@ + (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)
}
+ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ {
- assert(0);
- return NO;
+ return [object_getClass((id)self) jr_swizzleMethod:origSel_ withMethod:altSel_ error:error_];
+}
+
+
++ (BOOL)jr_aliasMethod:(SEL)methSel_ withSelector:(SEL)aliasSel_ error:(NSError**)error_ {
+ Method method = class_getInstanceMethod(self, methSel_);
+ if (!method) {
+ SetNSError(error_, @"method %@ not found for class %@", NSStringFromSelector(methSel_), NSStringFromClass(self));
+ return NO;
+ }
+ Method otherMethod = class_getInstanceMethod(self, aliasSel_);
+ if (otherMethod) {
+ SetNSError(error_, @"method -[%@ %@] already exists; won't alias to -%@", NSStringFromClass(self), NSStringFromSelector(aliasSel_), NSStringFromSelector(methSel_));
+ return NO;
+ }
+
+#if OBJC_API_VERSION >= 2
+ class_addMethod(self,
+ aliasSel_,
+ class_getMethodImplementation(self, methSel_),
+ method_getTypeEncoding(method));
+ return YES;
+#else
+ struct objc_method_list *alias_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)));
+ alias_list->obsolete = NULL; // soothe valgrind - apparently ObjC runtime accesses this value and it shows as uninitialized in valgrind
+ alias_list->method_count = 1;
+ alias_list->method_list = alias_method;
+
+ Method alias_method = hoisted_method_list->method_list;
+ bcopy(method, alias_method, sizeof(struct objc_method));
+ alias_method->method_name = aliasSel_;
+
+ class_addMethods(self, alias_list);
+
+ return YES;
+#endif
+}
+
+/* TODO: fix error generation so that these methods, rather than jr_aliasMethod:withSelector:error:,
+ will be reported as the method name in errors
+ */
++ (BOOL)jr_aliasMethod:(SEL)methSel_ withName:(const char*)aliasName_ error:(NSError**)error_ {
+ return [self jr_aliasMethod:methSel_ withSelector:sel_registerName(aliasName_) error:error_];
+}
++ (BOOL)jr_aliasClassMethod:(SEL)methSel_ withName:(const char*)aliasName_ error:(NSError**)error_ {
+ return [object_getClass((id)self) jr_aliasMethod:methSel_ withSelector:sel_registerName(aliasName_) error:error_];
+}
++ (BOOL)jr_aliasClassMethod:(SEL)methSel_ withSelector:(SEL)aliasSel_ error:(NSError**)error_ {
+ return [object_getClass((id)self) jr_aliasMethod:methSel_ withSelector:aliasSel_ error:error_];
}
@end
Something went wrong with that request. Please try again.