当前位置: 首页 > wzjs >正文

网站兼容所有浏览器国开机考网站界面设计

网站兼容所有浏览器,国开机考网站界面设计,html网页设计框架,wordpress百度数据库方法交换 method-swizzling是什么相关API方法交换的风险method-swizzling使用过程中的一次性问题在当前类中进行方法交换类方法的方法交换 方法交换的应用 method-swizzling是什么 method-swizzling的含义是方法交换,他的主要作用是在运行的时候将一个方法的实现替…

方法交换

  • method-swizzling是什么
  • 相关API
  • 方法交换的风险
    • method-swizzling使用过程中的一次性问题
    • 在当前类中进行方法交换
    • 类方法的方法交换
  • 方法交换的应用

method-swizzling是什么

method-swizzling的含义是方法交换,他的主要作用是在运行的时候将一个方法的实现替换为另一个方法的实现,这就是我们说的iOS黑魔法

OC中,利用method-swizzling实现AOP,AOP(面向切面编程)是一种编程思想,区别于OOP。

其中,AOP是面向切面进行提取封装,提取各个模块中的公共部分,提高模块的复用率,降低业务之间的耦合性;而OOP更加倾向于对业务模块的封装,划分出更加清晰的逻辑单元。

在之前学习探索消息流程的时候,我们了解到可以通过SEL方法查找器来查找method方法,而后得到对应的IMP。而方法交换其实就是将SEL与IMP原本的对应断开,并将SEL和新的IMP生成对应关系

这里笔者附上一张看到的图片来解释其关系:

在这里插入图片描述

相关API

//通过sel获取方法Method
class_getInstanceMethod://获取实例方法
class_getClassMethod://获取类方法method_getImplementation://获取一个方法的实现
method_setImplementation://设置一个方法的实现
method_getTypeEncoding://获取方法实现的编码类型
class_addMethod://添加方法实现
class_replaceMethod://用一个方法的实现,替换另一个方法的实现,即aIMP 指向 bIMP,但是bIMP不一定指向aIMP
method_exchangeImplementations://交换两个方法的实现,即 aIMP -> bIMP, bIMP -> aIMP

方法交换的风险

下面我们来看看方法交换中会遇到的问题

method-swizzling使用过程中的一次性问题

一次性:method-swizzling写在load方法中,但是load会主动的调用多次,这会导致方法的重复交换,令方法SEL指向又恢复成原来的IMP的问题出现

故而,这里我们可以通过单例模式的原则,令方法交换仅仅执行一次,这里我们需要使用GCD来实现单例,下面举一个例子说明该问题:

+ (void)load{static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{[LGRuntimeTool lg_bestMethodSwizzlingWithClass:self oriSEL:@selector(helloword) swizzledSEL:@selector(lg_studentInstanceMethod)];});
}

在当前类中进行方法交换

当我们进行方法交换的时候,必须交换的是当前类中的方法,若是方法在父类中,直接交换会导致父类的方法被错误的修改,这样会影响其所有的子类。

  • 方法交换的隔离性:必须确保交换的目标方法是当前类已实现或动态添加的方法,避免污染父类方法列表。
  • 动态注册的重要性:通过 class_addMethod 隔离父类实现,保证交换仅作用于当前类及其子类。
  • 风险规避:在子类分类中操作父类方法需谨慎,推荐使用 method_setImplementationclass_replaceMethod 控制影响范围。

这里我们先来看看若是直接和其父类进行方法交换会引起的后果:

在这里插入图片描述

在这里插入图片描述

上面的是父类中的方法,下面在子类的分类中方法交换,我们来看看会发生什么

在这里插入图片描述

根据断点显示,我们可以发现在子类Student中方法交换之后子类调用最后结果是正确的,但是到了最后一个断点的时候,可以发现程序报错了。我们来看看这是为什么?

这里我们先看子类Student调用personInstanceMethod方法,由于其imp交换成了lg_studentInstanceMethod,而在子类的分类中有该方法,所以不会报错。但是当父类Person中的imp也被交换成了lg_studentInstanceMethod,但我们并没有在父类中实现该方法,即相关的imp无法找到,就会导致程序崩溃掉。

那么我们怎么做就可以让程序不崩溃呢,这里我们可以通过class_addMethod尝试添加要交换的方法,下面先给出示例:

在这里插入图片描述

一般交换方法: 交换自己有的方法 – 走下面 因为自己有意味添加方法失败

交换自己没有实现的方法:

  • 首先第一步:会先尝试给自己添加要交换的方法 :personInstanceMethod (SEL) -> swiMethod(IMP)

  • 然后再将父类的IMP给swizzle personInstanceMethod(imp) -> swizzledSEL

当我们两个方法都没有实现的情况下,就会进入无限递归,导致最后栈溢出:

原因是 栈溢出递归死循环了,那么为什么会发生递归呢?----主要是因为 personInstanceMethod没有实现,然后在方法交换时,始终都找不到oriMethod,然后交换了寂寞,即交换失败,当我们调用personInstanceMethod(oriMethod)时,也就是oriMethod会进入LG中lg_studentInstanceMethod方法,然后这个方法中又调用了lg_studentInstanceMethod,此时的lg_studentInstanceMethod并没有指向oriMethod ,然后导致了自己调自己,即递归死循环

类方法的方法交换

其实类方法的方法交换和实例方法的方法交换差不多,这里我给出一个例子,这里和实例方法的区别其实只是类方法存在元类中

+ (void)lg_bestClassMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{if (!cls) NSLog(@"传入的交换类不能为空");Method oriMethod = class_getClassMethod([cls class], oriSEL);Method swiMethod = class_getClassMethod([cls class], swizzledSEL);if (!oriMethod) { // 避免动作没有意义// 在oriMethod为nil时,替换后将swizzledSEL复制一个不做任何事的空实现,代码如下:class_addMethod(object_getClass(cls), oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));method_setImplementation(swiMethod, imp_implementationWithBlock(^(id self, SEL _cmd){NSLog(@"来了一个空的 imp");}));}// 一般交换方法: 交换自己有的方法 -- 走下面 因为自己有意味添加方法失败// 交换自己没有实现的方法://   首先第一步:会先尝试给自己添加要交换的方法 :personInstanceMethod (SEL) -> swiMethod(IMP)//   然后再将父类的IMP给swizzle  personInstanceMethod(imp) -> swizzledSEL//oriSEL:personInstanceMethodBOOL didAddMethod = class_addMethod(object_getClass(cls), oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));if (didAddMethod) {class_replaceMethod(object_getClass(cls), swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));}else{method_exchangeImplementations(oriMethod, swiMethod);}}

方法交换的应用

方法交换最常用的一个应用是防止数组、字典等越界崩溃。在iOS中,NSNumberNSArrayNSDictionary这些都是类簇,一个NSArray的实现可能由多个类组成,所以我们必须获取到其"真身"进行交换,直接对NSarray进行操作是无效的。

下面列举了NSArray和NSDictionary本类的类名,可以通过Runtime函数取出本类。

类名真身
NSArray__NSArrayI
NSMutableArray__NSArrayM
NSDictionary__NSDictionaryI
NSMutableDictionary__NSDictionaryM

这里我以NSArray为例来看看方法交换的应用:

#import "NSArray+crush.h"
#import "objc/objc-runtime.h"
@implementation NSArray (crush)
+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{NSLog(@"load");Method fromMethod = class_getInstanceMethod(objc_getClass("NSConstantArray"), @selector(objectAtIndex:));Method toMethod = class_getInstanceMethod(objc_getClass("NSConstantArray"), @selector(new_objectAtIndex:));method_exchangeImplementations(fromMethod, toMethod);});}
- (id)new_objectAtIndex:(NSUInteger)index {NSLog(@"new_objectAtIndex");if (index >= self.count) {// 越界处理NSLog(@"Index %lu out of bounds, array count is %lu.", (unsigned long)index, (unsigned long)self.count);return nil;} else {// 正常访问,注意这里调用的是替换后的方法,因为实现已经交换return [self new_objectAtIndex:index];}}@end

这里我们新建一个NSArray的分类,交换一下objectAtIndexnew_objectAtIndex方法,我们来看看结果:

在这里插入图片描述

这里的NSArray类型是NSConstantArray,虽然我们已经越界了但是程序并没有退出,我们打印了一个报错,这样就保证了这个函数的安全.

http://www.dtcms.com/wzjs/536830.html

相关文章:

  • 上海最专业的网站建设公司排名摄影app
  • 制作一个网站怎么做app商店下载
  • 嘉定论坛网站建设建设网站的
  • 网站建设需要学习课程东莞哪里能学建设网站
  • 怎样弄一个自己的平台石家庄seo全网营销
  • 辉南网站建设网页设计与制作成品是啥样的
  • 国外有名的设计网站麦云短链接
  • 淘宝做首页热点的什么网站电商网站建设公司怎么样
  • 网上开店网站泉山网站开发
  • 象山县建设工程招投标网站wordpress菜单html5
  • 宣传网站怎么做的北京网站排名
  • 东莞做网站(信科网络)档案网站建设网页
  • 北京朝阳区建设工作办公网站win2003搭建php网站
  • 聊城集团网站建设费用做网站规避什么
  • 单位网站建设程序wordpress 数据优化
  • 食品营销型网站有成功案例的网站
  • 百度网站建设的意义最专业的网站设计
  • 网站的定位与功能php 企业网站模板
  • 甘肃住房城乡建设厅网站首页瀚钦科技网站建设
  • 凡总创业网站wordpress设置为繁体字
  • 功能网站首页模板广州顶正餐饮培训学校
  • 国外的哪个网站可以做跳转望城警务督察网站建设
  • 网站系统评测要怎么做呢怎样营销能有效获取客户
  • 廊坊网站建设开发服务器做网站用什么系统
  • 如何建设一个优秀的电商网站怎么自己做淘宝客网站吗
  • 本地搭建wordpress建站教程四川省城乡建设信息网站证件查询
  • 网站定制公司哪家好国外高清视频素材网站推荐
  • 国外网站鞋子做的好的网站seo公司优化方案
  • 怎么快速提升网站权重企业网站建设免费
  • 阿里云有域名之后怎么建设网站广西网站运营