@@ -0,0 +1,155 @@
# import "TDNewSwizzle.h"
# if TARGET_OS _IOS
# import < objc / runtime . h >
# import < objc / message . h >
# else
# import < objc / objc - class . h >
# endif
# define TDSetNSErrorFor ( FUNC , ERROR_VAR , FORMAT , . . . ) \
if ( ERROR_VAR ) { \
NSString * errStr = [ NSString stringWithFormat : @ "%s: " FORMAT , FUNC , # # __VA _ARGS __ ] ; \
* ERROR_VAR = [ NSError errorWithDomain : @ "NSCocoaErrorDomain" \
code : -1 \
userInfo : [ NSDictionary dictionaryWithObject : errStr forKey : NSLocalizedDescriptionKey ] ] ; \
}
# define TDSetNSError ( ERROR_VAR , FORMAT , . . . ) TDSetNSErrorFor ( __func __ , ERROR_VAR , FORMAT , # # __VA _ARGS __ )
# if OBJC_API _VERSION >= 2
# define TDGetClass ( obj ) object_getClass ( obj )
# else
# define TDGetClass ( obj ) ( obj ? obj -> isa : Nil )
# endif
@ implementation NSObject ( TDNewSwizzle )
+ ( BOOL ) td_new _swizzleMethod : ( SEL ) origSel_ withClass : ( Class ) altCla_ withMethod : ( SEL ) altSel_ error : ( NSError * * ) error_ {
Method origMethod = class_getInstanceMethod ( self , origSel_ ) ;
if ( ! origMethod ) {
TDSetNSError ( error_ , @ "original method %@ not found for class %@" , NSStringFromSelector ( origSel_ ) , [ self class ] ) ;
return NO ;
}
Method altMethod = class_getInstanceMethod ( altCla_ , altSel_ ) ;
if ( ! altMethod ) {
TDSetNSError ( error_ , @ "alternate method %@ not found for class %@" , NSStringFromSelector ( altSel_ ) , [ altCla_ class ] ) ;
return NO ;
}
class_addMethod ( self ,
origSel_ ,
class_getMethodImplementation ( self , origSel_ ) ,
method_getTypeEncoding ( origMethod ) ) ;
class_addMethod ( altCla_ ,
altSel_ ,
class_getMethodImplementation ( altCla_ , altSel_ ) ,
method_getTypeEncoding ( altMethod ) ) ;
// 交 换 之 前 , 先 对 自 定 义 方 法 进 行 添 加
BOOL didAddMethod = class_addMethod ( self ,
altSel_ ,
method_getImplementation ( altMethod ) ,
method_getTypeEncoding ( altMethod ) ) ;
if ( didAddMethod ) {
method_exchangeImplementations ( origMethod , class_getInstanceMethod ( self , altSel_ ) ) ;
}
return didAddMethod ;
}
+ ( BOOL ) td_new _swizzleMethod : ( SEL ) origSel_ withMethod : ( SEL ) altSel_ error : ( NSError * * ) error_ {
# if OBJC_API _VERSION >= 2
Method origMethod = class_getInstanceMethod ( self , origSel_ ) ;
if ( ! origMethod ) {
TDSetNSError ( error_ , @ "original method %@ not found for class %@" , NSStringFromSelector ( origSel_ ) , [ self class ] ) ;
return NO ;
}
Method altMethod = class_getInstanceMethod ( self , altSel_ ) ;
if ( ! altMethod ) {
TDSetNSError ( error_ , @ "alternate method %@ not found for class %@" , NSStringFromSelector ( altSel_ ) , [ self class ] ) ;
return NO ;
}
class_addMethod ( self ,
origSel_ ,
class_getMethodImplementation ( self , origSel_ ) ,
method_getTypeEncoding ( origMethod ) ) ;
class_addMethod ( self ,
altSel_ ,
class_getMethodImplementation ( self , altSel_ ) ,
method_getTypeEncoding ( altMethod ) ) ;
method_exchangeImplementations ( class_getInstanceMethod ( self , origSel_ ) , class_getInstanceMethod ( self , altSel_ ) ) ;
return YES ;
# else
// Scan for non - inherited methods .
Method directOriginalMethod = NULL , directAlternateMethod = NULL ;
void * iterator = NULL ;
struct objc_method _list * mlist = class_nextMethodList ( self , & iterator ) ;
while ( mlist ) {
int method_index = 0 ;
for ( ; method_index < mlist -> method_count ; method_index + + ) {
if ( mlist -> method_list [ method_index ] . method_name = = origSel_ ) {
assert ( ! directOriginalMethod ) ;
directOriginalMethod = & mlist -> method_list [ method_index ] ;
}
if ( mlist -> method_list [ method_index ] . method_name = = altSel_ ) {
assert ( ! directAlternateMethod ) ;
directAlternateMethod = & mlist -> method_list [ method_index ] ;
}
}
mlist = class_nextMethodList ( self , & iterator ) ;
}
// If either method is inherited , copy it up to the target class to make it non - inherited .
if ( ! directOriginalMethod || ! directAlternateMethod ) {
Method inheritedOriginalMethod = NULL , inheritedAlternateMethod = NULL ;
if ( ! directOriginalMethod ) {
inheritedOriginalMethod = class_getInstanceMethod ( self , origSel_ ) ;
if ( ! inheritedOriginalMethod ) {
TDSetNSError ( error_ , @ "original method %@ not found for class %@" , NSStringFromSelector ( origSel_ ) , [ self className ] ) ;
return NO ;
}
}
if ( ! directAlternateMethod ) {
inheritedAlternateMethod = class_getInstanceMethod ( self , altSel_ ) ;
if ( ! inheritedAlternateMethod ) {
TDSetNSError ( error_ , @ "alternate method %@ not found for class %@" , NSStringFromSelector ( altSel_ ) , [ self className ] ) ;
return NO ;
}
}
int hoisted_method _count = ! directOriginalMethod && ! directAlternateMethod ? 2 : 1 ;
struct objc_method _list * hoisted_method _list = malloc ( sizeof ( struct objc_method _list ) + ( sizeof ( struct objc_method ) * ( hoisted_method _count -1 ) ) ) ;
hoisted_method _list -> obsolete = NULL ; // soothe valgrind - apparently ObjC runtime accesses this value and it shows as uninitialized in valgrind
hoisted_method _list -> method_count = hoisted_method _count ;
Method hoisted_method = hoisted_method _list -> method_list ;
if ( ! directOriginalMethod ) {
bcopy ( inheritedOriginalMethod , hoisted_method , sizeof ( struct objc_method ) ) ;
directOriginalMethod = hoisted_method + + ;
}
if ( ! directAlternateMethod ) {
bcopy ( inheritedAlternateMethod , hoisted_method , sizeof ( struct objc_method ) ) ;
directAlternateMethod = hoisted_method ;
}
class_addMethods ( self , hoisted_method _list ) ;
}
// Swizzle .
IMP temp = directOriginalMethod -> method_imp ;
directOriginalMethod -> method_imp = directAlternateMethod -> method_imp ;
directAlternateMethod -> method_imp = temp ;
return YES ;
# endif
}
+ ( BOOL ) td_new _swizzleClassMethod : ( SEL ) origSel_ withClassMethod : ( SEL ) altSel_ error : ( NSError * * ) error_ {
return [ TDGetClass ( ( id ) self ) td_new _swizzleMethod : origSel_ withMethod : altSel_ error : error_ ] ;
}
@ end