码迷,mamicode.com
首页 > 移动开发 > 详细

Method Swizzle黑魔法,修改 ios 系统类库方法(转载)

时间:2015-07-15 14:59:23      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:

一般来说,系统提供的方法已经足够开发了,但是有的时候有些需求用普通方法不好做。

如:在所有的viewcontroll 的viewwillappear:方法之前打个log

你可能会这么做:

1. 建一个uiviewcontroll 父类,重写viewwillappear方法,调用super viewwillappear 方法之前加上log

2. 所有新建的uiviewcontroller 继承第一步生成的

确实你是完成这样的功能,可是你做了那么多的修改,基本每个uiviewcontroller都去修改了父类,这种方法太过于笨重了

 

本文提供了简单地方法即可实现

我的理解中,object-c 的类调用方法是根据三个元素来定义的。 

1. 方法,代表类定义中一个方法类型(typedef struct objc_method *Method)

2. SEL 选择器(typedef struct objc_selector *SEL),一个方法在运行时的名字,常见的有 [self performSelector:@selector(somemethod:) withObject:nil afterDelay:0.5]; @selector(somemethod:)作为方法的入口

3. 方法的实现入口(typedef id (*IMP)(id, SEL, …))

这三个元素确定了具体调用哪一个函数

 

直接看代码

 

  1. #import "UIViewController+Tracking.h"  
  2. #import <objc/runtime.h>  
  3.   
  4. @implementation UIViewController (Tracking)  
  5.   
  6. + (void)load {  
  7.     NSString *className = NSStringFromClass(self.class);  
  8.     NSLog(@"classname %@", className);  
  9.     static dispatch_once_t onceToken;  
  10.     dispatch_once(&onceToken, ^{  
  11.         Class class = [self class];  
  12.           
  13.         // When swizzling a class method, use the following:  
  14.         // Class class = object_getClass((id)self);  
  15.           
  16.         SEL originalSelector = @selector(viewWillAppear:);  
  17.         SEL swizzledSelector = @selector(xxx_viewWillAppear:);  
  18.           
  19.         Method originalMethod = class_getInstanceMethod(class, originalSelector);  
  20.         Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);  
  21.           
  22.         BOOL didAddMethod =  
  23.         class_addMethod(class,  
  24.                         originalSelector,  
  25.                         method_getImplementation(swizzledMethod),  
  26.                         method_getTypeEncoding(swizzledMethod));  
  27.           
  28.         if (didAddMethod) {  
  29.             class_replaceMethod(class,  
  30.                                 swizzledSelector,  
  31.                                 method_getImplementation(originalMethod),  
  32.                                 method_getTypeEncoding(originalMethod));  
  33.         } else {  
  34.             method_exchangeImplementations(originalMethod, swizzledMethod);  
  35.         }  
  36.     });  
  37. }  

 

我们category重写了NSObject的 load 方法oc提供了objc/runtime.h类让我们获取这些东西,同时还提供了对类方法操作的函数

我们想的是,直接用一个方法替换掉系统的方法,然后把一些自定义的动作加到方法中

我们只想运行一次就够了,所以使用了 dispatch_once(&onceToken, ^{ …… }
接下来给类添加了新方法

把新方法和系统方法替换

 

 

  1. #pragma mark - Method Swizzling  
  2.   
  3. - (void)xxx_viewWillAppear:(BOOL)animated {  
  4.     NSLog(@"viewWillAppear: %@", self);  
  5.     [self xxx_viewWillAppear:animated];  
  6. }  

但是新方法实现的时候,调用的是 [self xxx_viewwillAppear:animated]; 可能你会疑惑

 

这是因为我们在上面已经用xxx_viewwillAppear 和 viewwillAppear 互换了。所以实际上执行的是系统的viewwillAppear

这个时候可能你又有疑问了,为什么实现是- (void)xxx_viewWillAppear:(BOOL)animated{} 这样的

这是因为 SEL swizzledSelector = @selector(xxx_viewWillAppear:); 拿的就是我们新写的方法。

可以结合这篇博客看,配图很容易懂

http://blog.csdn.net/yiyaaixuexi/article/details/9374411

 

以及这篇对SEL讲的比较清楚

http://blog.csdn.net/fengsh998/article/details/8612969

代码下载地址

https://github.com/holysin/Method_swizzle

Method Swizzle黑魔法,修改 ios 系统类库方法(转载)

标签:

原文地址:http://www.cnblogs.com/HughLiu/p/4648105.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!