??斗地主捕鱼电竞提现秒到 广告位招租 - 15元/月全站展示
??支付宝搜索579087183领大额红包 ??伍彩集团官网直营彩票
??好待遇→招代理 ??伍彩集团官网直营彩票
??络茄网 广告位招租 - 15元/月全站展示
iOS 开发:Method Swizzling

转载   PSPDF   2018-10-27   浏览量:21


天天好釆免费资料大全:iOS 开发之Method Swizzling

前言

彩票开奖查询 www.kbyp.net 如果你还不知道什么是Method Swizzling,你可以看看NSHipster 的文章 ,我简单介绍一下,method swizzling 可以看成劫持了一个方法。


我们可以看看NSHipster 的文章中有以下代码:

- (void)xxx_viewWillAppear:(BOOL)animated {
    [self xxx_viewWillAppear:animated];
    NSLog(@"viewWillAppear: %@", self);
}

是不是觉得递归无限循环,事实上并不会,你可以这么理解,一个具体的SEL是个名字,一个具体的IMP是个函数指针,在类里面它们是靠一个表建立联系。


假设(纯属虚构) UIViewController 的 @selector(viewWillAppear:) 对应的内部实现为以下

void _UIKIT_Internal_UIViewController_viewWillAppear(id vc, SEL selector, BOOL animated) {
  ...// ^_^苹果私有代码
}

假设UIViewController 的 @selector(xxx_viewWillAppear:) 的实现为以下

void my_xxx_viewWillAppear(id vc, SEL selector, BOOL animated) {
  [vc performSelector:@selector(xxx_viewWillAppear) withObject:@(animated)];  
  NSLog(@"viewWillAppear: %@", vc);
}

那么未替换方法前@selector(viewWillAppear:)对应的指针就是&_UIKIT_Internal_UIViewController_viewWillAppear

那么未替换方法前@selector(xxx_viewWillAppear:)对应的指针就是&my_xxx_viewWillAppear


一旦替换方法后,@selector(viewWillAppear:)对应的指针就是&my_xxx_viewWillAppear,
@selector(xxx_viewWillAppear:)对应的指针就是&_UIKIT_Internal_UIViewController_viewWillAppear


my_xxx_viewWillAppear 中的 [vc performSelector:@selector(xxx_viewWillAppear) withObject:@(animated)];
相当于什么,相当于 调用@selector(xxx_viewWillAppear:)所指的函数&_UIKIT_Internal_UIViewController_viewWillAppear, 也就是相当于调用原来的函数,所以这并不是递归。


存在的危险

  1. 有些NSObject类是类簇,替换方法要找到真正的类,如NSArray替换方法,通常用'_NSArrayM'或'_NSArrayI'
  2. 执行顺序问题,ViewController是自己写的类,ViewController的load方法和UIViewController的category里的load方法哪个先执行,如果是ViewController的先执行,那么UIViewController的swizzling就对ViewController无效,如果ViewController的后执行就一切正常,代码如下
@implementation UIViewController (Tracking)

+ (void)load {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    [self replaceOriginalSelector:@selector(viewWillAppear:) withNewSelector:@selector(xxx_viewWillAppear:)];
  });
}

- (void)xxx_viewWillAppear:(BOOL)animated {
  [self xxx_viewWillAppear:animated];
  NSLog(@"x_viewWillAppear: %@", self);
}
@end

@interface ViewController ()

@end

@implementation ViewController

+ (void)load {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    [self replaceOriginalSelector:@selector(viewWillAppear:) withNewSelector:@selector(yyy_viewWillAppear:)];
  });
}

- (void)yyy_viewWillAppear:(BOOL)animated {
  [self yyy_viewWillAppear:animated];
  NSLog(@"y_viewWillAppear: %@", self);
}

@end

3.也是顺序问题
以下,来自另一篇文章defagos.github.io
它是这么说的,NSObject 实现了 -awakeFromNib,但是它的子类UIView,孙类UILabel都没有在本类实现- awakeFromNib,那么替换时如果不写在category +(void) load方法里,那么顺序也是个问题

假设我们先替换了UILabel的- awakeFromNib方法,然后再替换了UIView的- awakeFromNib,那么UILabel的- awakeFromNib方法就不会执行UIView的- awakeFromNib方法,因为它们都是独立替换的是NSObject方法,这篇文章defagos.github.io 提供了一个解决方案,当本类没有实现方法(如 UILabel -awakeFromNib)时,首先先添加一个block方法 调用[super awakeFromNib];,我初次看到也是觉得这个方式很好,但是我发现两点不足,

  1. 在构建objc_super时,如果父类本身没有实现方法,.super_class = class_getSuperclass(clazz),这么写好像是没有用的,似乎super_class要填真正实现方法的祖先类,而不能一概的写class_getSuperclass

    struct objc_super super = {
            .receiver = self,
            .super_class = class_getSuperclass(clazz)
        };
  2. va_list的使用
id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;

由于 va_list 变量最后是靠宏 va_arg(ap, type) 来获取的,type又是未知的,这个函数指针的强制转换转换可能会出现问题


结语

可见,Swizzling正确的顺序是十分重要的,(共同点:类本身没有真正实现方法)

  • 如果你的Swizzling是静态的,那么就保证父类的Swizzling发生在子类的Swizzling前
  • 如果你的Swizzling是动态的或者你管不好他们先后顺序,那么就要用defagos的方法动态的call objc_msgSendSuper,
  • 或许你勤快一点还可以直接在category里面重写,
    - (void)awakeFromNib {
    [super awakeFromNib];
    }

转载自://blog.51cto.com/14033137/2309805

招聘 不方便扫码就复制添加关注:程序员招聘谷,微信号:jobs1024



iOS开发初学者入门需要学习哪些知识?
都说互联网的快速发展改变着人们的就业生活方式,于是像程序员这样的技术性岗位就成为大家争相追逐的岗位,作为一项技术性iOS开发岗位,高门槛,高收入总是伴随着这一行业,所以现在越来越多的新人选择从事iOS开发工作,其中不乏一些转行的程序员。
iOS将相册中图片上传至服务器的方法
这篇文章主要为大家详细介绍了iOS将相册中图片上传至服务器的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
iOS仿微信摇一摇功能
这篇文章主要为大家详细介绍了iOS仿微信摇一摇功能的实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
iOS仿网易简单头部滚动效果
这篇文章主要为大家详细介绍了iOS仿网易简单头部滚动效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
iOS如何定义名为任意的变量详解
这篇文章主要给大家介绍了关于iOS如何定义名为任意的变量的相关资料,文中通过示例代码介绍的非常详细,对各位iOS开发者们具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
iOS利用NSMutableAttributedString实现富文本的方法小结
这篇文章主要给大家介绍了关于iOS利用NSMutableAttributedString如何实现富文本的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
iOS中精确计算WebView高度的方法示例
这篇文章主要给大家介绍了关于iOS中如何精确计算WebView高度,以及iOS开发之解决WebView自适应内容高度的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧
iOS push侧滑返回功能实现方法
这篇文章主要为大家详细介绍了iOSpush侧滑返回功能实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
iOS禁用右滑返回的两种方法
这篇文章主要为大家详细介绍了iOS禁用右滑返回的两种方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下