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

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

如:在所有的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, …))

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

 

直接看代码

 

[objc]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
 
  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, ^{ …… }
接下来给类添加了新方法

把新方法和系统方法替换

 

 

[objc]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
 
  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

1  Method nameMethod = class_getInstanceMethod(Class class,SEL name);//得到实例方法

参数:class类名  name 方法名

理解:通过类名和方法名来得到方法(c函数)

 

2 method_getImplementation(Method method)

参数:method 方法

理解:通过方法来得到它的实现

 

 

3 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

理解:将所给的name(方法名)的方法实现,被imp(方法的实现)代替

cls:被添加方法的类

name:可以理解为方法名,这个貌似随便起名,

imp:实现这个方法的函数 

types:一个定义该函数返回值类型和参数类型的字符串,这个具体会在后面讲

 

4 class_replaceMethod(Class class,SEL  B, method_getImplementation(Method AMethod), method_getTypeEncoding(Method AMethod));

参数:class :方法所属的类 B:将被替换其实现的方法名    AMethod:由A生成的方法(c函数)

理解:用A的方法实现来代替B的方法实现

5 method_exchangeImplementations(SEL A, SEL B);

理解:交换两个方法的实现

void swizzle_method(Class class,SEL originalSelector,SEL swizzledSelector) {

    Method originalMethod = class_getInstanceMethod(class, originalSelector);//得到实例方法

    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    BOOL didSwizzleMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));

    if (didSwizzleMethod) {

        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));

    } else {

        method_exchangeImplementations(originalMethod, swizzledMethod);

    }

}

 

 

转载于:https://www.cnblogs.com/HughLiu/p/4648105.html

本项目是一个基于SSM(Spring+SpringMVC+MyBatis)后端框架与Vue.js前端框架开发的疫情居家办公系统。该系统旨在为居家办公的员工提供一个高效、便捷的工作环境,同时帮助企业更好地管理远程工作流程。项目包含了完整的数据库设计、前后端代码实现以及详细的文档说明,非常适合计算机相关专业的毕设学生和需要进行项目实战练习的Java学习者。 系统的核心功能包括用户管理、任务分配、进度跟踪、文件共享和在线沟通等。用户管理模块允许管理员创建和管理用户账户,分配不同的权限。任务分配模块使项目经理能够轻松地分配任务给团队成员,并设置截止日期。进度跟踪模块允许员工实时更新他们的工作状态,确保项目按计划进行。文件共享模块提供了一个安全的平台,让团队成员可以共享和协作处理文档。在线沟通模块则支持即时消息和视频会议,以增强团队之间的沟通效率。 技术栈方面,后端采用了Spring框架来管理业务逻辑,SpringMVC用于构建Web应用程序,MyBatis作为ORM框架简化数据库操作。前端则使用Vue.js来实现动态用户界面,搭配Vue Router进行页面导航,以及Vuex进行状态管理。数据库选用MySQL,确保数据的安全性和可靠性。 该项目不仅提供了一个完整的技术实现示例,还为开发者留下了扩展和改进的空间,可以根据实际需求添加新功能或优化现有功能。
本项目是一个基于SSM(Spring+SpringMVC+MyBatis)后端框架与Vue.js前端框架开发的网上球鞋竞拍系统。该项目旨在为球鞋爱好者提供一个便捷、高效的在线竞拍平台,用户可以在此平台上浏览、搜索、竞拍心仪的球鞋,并参与到各种有趣的竞拍活动中。 系统的主要功能包括用户注册登录、球鞋信息展示、竞拍活动创建与管理、实时竞拍以及交易安全保障等。用户可以通过注册账号后,浏览平台上发布的各类球鞋信息,包括品牌、型号、颜色、尺码以及当前竞拍状态等。系统支持用户创建和管理自己的竞拍活动,设定竞拍规则和时间,同时提供实时竞拍功能,确保公平、透明的交易过程。 在技术实现上,后端采用SSM框架进行开发,Spring负责业务逻辑层,SpringMVC处理Web请求,MyBatis进行数据库操作,保证了系统的稳定性和扩展性。前端则使用Vue.js框架,结合Axios进行数据请求,实现了前后端分离,提高了开发效率和用户体验。 数据库设计方面,系统采用了MySQL数据库,存储用户信息、球鞋信息、竞拍活动等数据,确保数据的安全性和完整性。此外,项目还包含了详细的文档资料,包括需求分析、系统设计、数据库设计以及测试报告等,为项目的实施和维护提供了有力的支持。 该项目不仅适合作为计算机相关专业学生的毕业设计题目,也适合Java学习者进行实战练习,通过在此基础上进行功能扩展和改进,可以进一步提升编程技能和项目管理能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值