Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 135 lines (117 sloc) 4.959 kB
be44d22 @rentzsch Update copyright headers
authored
1 // JRSwizzle.m semver:1.0
2 // Copyright (c) 2007-2011 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
3 // Some rights reserved: http://opensource.org/licenses/MIT
4 // https://github.com/rentzsch/jrswizzle
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
5
6 #import "JRSwizzle.h"
60ccb35 @serebryakov-av Added iOS support
serebryakov-av authored
7
8 #if TARGET_OS_IPHONE
9 #import <objc/runtime.h>
10 #import <objc/message.h>
11 #else
12 #import <objc/objc-class.h>
13 #endif
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
14
3db27c2 @outis [DEV] added method aliasing
outis authored
15 #define SetNSErrorFor(FUNC, ERROR_VAR, FORMAT,...) \
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
16 if (ERROR_VAR) { \
3db27c2 @outis [DEV] added method aliasing
outis authored
17 NSString *errStr = [NSString stringWithFormat:@"%s: " FORMAT,FUNC,##__VA_ARGS__]; \
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
18 *ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \
19 code:-1 \
20 userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \
21 }
3db27c2 @outis [DEV] added method aliasing
outis authored
22 #define SetNSError(ERROR_VAR, FORMAT,...) SetNSErrorFor(__func__, ERROR_VAR, FORMAT, ##__VA_ARGS__)
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
23
4379f60 @JensAyton Removed jr_aliasFoo family, which don't compile for Mac OS X 10.4.
JensAyton authored
24 #if OBJC_API_VERSION >= 2
25 #define GetClass(obj) object_getClass(obj)
26 #else
27 #define GetClass(obj) (obj ? obj->isa : Nil)
28 #endif
29
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
30 @implementation NSObject (JRSwizzle)
31
32 + (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ {
33 #if OBJC_API_VERSION >= 2
34 Method origMethod = class_getInstanceMethod(self, origSel_);
35 if (!origMethod) {
60ccb35 @serebryakov-av Added iOS support
serebryakov-av authored
36 #if TARGET_OS_IPHONE
37 SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self class]);
38 #else
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
39 SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]);
60ccb35 @serebryakov-av Added iOS support
serebryakov-av authored
40 #endif
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
41 return NO;
42 }
43
44 Method altMethod = class_getInstanceMethod(self, altSel_);
45 if (!altMethod) {
60ccb35 @serebryakov-av Added iOS support
serebryakov-av authored
46 #if TARGET_OS_IPHONE
47 SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self class]);
48 #else
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
49 SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]);
60ccb35 @serebryakov-av Added iOS support
serebryakov-av authored
50 #endif
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
51 return NO;
52 }
53
54 class_addMethod(self,
55 origSel_,
56 class_getMethodImplementation(self, origSel_),
57 method_getTypeEncoding(origMethod));
58 class_addMethod(self,
59 altSel_,
60 class_getMethodImplementation(self, altSel_),
61 method_getTypeEncoding(altMethod));
62
63 method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_));
64 return YES;
65 #else
66 // Scan for non-inherited methods.
67 Method directOriginalMethod = NULL, directAlternateMethod = NULL;
68
69 void *iterator = NULL;
70 struct objc_method_list *mlist = class_nextMethodList(self, &iterator);
71 while (mlist) {
72 int method_index = 0;
73 for (; method_index < mlist->method_count; method_index++) {
74 if (mlist->method_list[method_index].method_name == origSel_) {
75 assert(!directOriginalMethod);
76 directOriginalMethod = &mlist->method_list[method_index];
77 }
78 if (mlist->method_list[method_index].method_name == altSel_) {
79 assert(!directAlternateMethod);
80 directAlternateMethod = &mlist->method_list[method_index];
81 }
82 }
83 mlist = class_nextMethodList(self, &iterator);
84 }
85
86 // If either method is inherited, copy it up to the target class to make it non-inherited.
87 if (!directOriginalMethod || !directAlternateMethod) {
88 Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL;
89 if (!directOriginalMethod) {
90 inheritedOriginalMethod = class_getInstanceMethod(self, origSel_);
91 if (!inheritedOriginalMethod) {
92 SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]);
93 return NO;
94 }
95 }
96 if (!directAlternateMethod) {
97 inheritedAlternateMethod = class_getInstanceMethod(self, altSel_);
98 if (!inheritedAlternateMethod) {
99 SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]);
100 return NO;
101 }
102 }
103
104 int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1;
105 struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1)));
2f677d0 @rentzsch [FIX] Soothe valgrind by nulling out `hoisted_method_list->obsolete`,…
authored
106 hoisted_method_list->obsolete = NULL; // soothe valgrind - apparently ObjC runtime accesses this value and it shows as uninitialized in valgrind
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
107 hoisted_method_list->method_count = hoisted_method_count;
108 Method hoisted_method = hoisted_method_list->method_list;
109
110 if (!directOriginalMethod) {
111 bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method));
112 directOriginalMethod = hoisted_method++;
113 }
114 if (!directAlternateMethod) {
115 bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method));
116 directAlternateMethod = hoisted_method;
117 }
118 class_addMethods(self, hoisted_method_list);
119 }
120
121 // Swizzle.
122 IMP temp = directOriginalMethod->method_imp;
123 directOriginalMethod->method_imp = directAlternateMethod->method_imp;
124 directAlternateMethod->method_imp = temp;
125
126 return YES;
127 #endif
128 }
129
130 + (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ {
4379f60 @JensAyton Removed jr_aliasFoo family, which don't compile for Mac OS X 10.4.
JensAyton authored
131 return [GetClass((id)self) jr_swizzleMethod:origSel_ withMethod:altSel_ error:error_];
3db27c2 @outis [DEV] added method aliasing
outis authored
132 }
133
cb43f61 @rentzsch [ADMIN] Initial commit (via `svn export http://rentzsch.com/svn/trunk…
authored
134 @end
Something went wrong with that request. Please try again.