方法混合(Method Swizzling):动态替换已有类的方法
动态替换类的方法在不能改变原有代码的情况下,提供了一种解决方法。貌似这种方法不太常用,不过记下来以备后患~。
功能:用这种方法可以给你的程序提供一些一般方法不能实现的功能。
例子:UIWebView的delegate接口提供了一个shouldStartLoadWithRequest()方法,可以通过NSURLRequest这个对象得到所要装载网页 的详情(head头信息等),但你不能修改这个对象(添加或修改你需要的HTTP请求头信息,比如:“User-Agent”字段),如果HTTP请求的对端,(比如硬件设备)需要各种特殊的头信息,将束手无策。
但如果使用方法混合(Method Swizzling)计数就可以实现动态修改接受类的方法。
注意:技术比较强大,但比较危险(具体还未知。。。待确定)
实现:(以代码为例子)将SimpleClass类的print方法动态替换成Swizzle类的swizzlePrint方法:
//Swizzle.h #import <Foundation/Foundation.h> @interface Swizzle : NSObject { } + (BOOL)swizzle:(Class)c1 oSelector:(SEL)orig Class:(Class)c2 aSelector:(SEL)newSel; - (void)testSwizzle; @end //Swizzle.m #import "Swizzle.h" #import <objc/runtime.h> #import <objc/message.h> @interface SimpleClass : NSObject { } - (void)print:(NSString *)str; @end @implementation SimpleClass /*the old method to replace*/ - (void)print:(NSString *)str { NSLog(@"Input String is : %@", str); } @end @implementation Swizzle /***************************************************************************** 功能描述 : 将类c1中方法orig的实现替换为类c2中方法newSel的实现 输入参数 : (Class)c1 (SEL)orig (Class)c2 (SEL)newSel 返 回 值 : BOOL *****************************************************************************/ + (BOOL)swizzle:(Class)c1 oSelector:(SEL)orig Class:(Class)c2 aSelector:(SEL)newSel{ /*注意区分实例方法和类方法:实例方法用getInstanceMethod,类方法:getClassMethod*/ Method origMethod = class_getInstanceMethod(c1, orig); Method newMethod = class_getInstanceMethod(c2, newSel); if (NULL == origMethod) { NSLog(@"can't find orig method %@ in class %@",NSStringFromSelector(origMethod),c1); return NO; } if (NULL == newMethod) { NSLog(@"can't find new method %@ in class %@",NSStringFromSelector(newSel),c2); return NO; } /*class_addMethod:add a new method to a class with a given name and implementation(详见官方文档)*/ BOOL added = class_addMethod(c1, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); if(added) { /*if added success just replace :NO TEST---MAY HAVE SOME PROBLEM*/ class_replaceMethod(c1, newSel, method_getImplementation(origMethod)), method_getTypeEncoding(origMethod)); }else { /*change two method's implementation*/ method_exchangeImplementations(origMethod, newMethod); } return YES; } /*The new method*/ - (void)swizzlePrint:(NSString *)str { NSLog(@"After Swizzle:%@",str); } /*a test method*/ - (void)testSwizzle { SEL oriSel = @selector(print:); SEL newSel = @selector(swizzlePrint:); SimpleClass *simple = [[SimpleClass alloc] init]]; [simple print:@"Hello World"]; [Swizzle swizzle:[simple class] oSelector:oriSel Class:[self class] aSelector:newSel]; [simple print:@"Hello World"]; [simple release]; }