前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS NSPROXY ARC填坑记

iOS NSPROXY ARC填坑记

作者头像
粲然忧生
发布2022-08-02 15:04:07
5300
发布2022-08-02 15:04:07
举报
文章被收录于专栏:工程师的分享

        谨以此文纪念多个日夜不停定位问题填坑的日子。

        近期,有个bug映入眼帘,主要是某段程序对http的数据进行截取,用于进行二次数据分析,然后截取数据的方式主要对系统自带的方式发送请求可以截获,也可以回调,用第三方的库则不能回调,不知道哪里环节出来问题。

首先,苹果在 iOS9 之后已经放弃了 NSURLSession所以在现在的实际开发中,一般使用的是 iOS7 之后推出的NSURLSession。

https://www.jianshu.com/p/a8fc22afb739对NSURLSession进行了比较全面的讲解,另外,AFNetWorking的源码解析也比较多,比如:

https://www.cnblogs.com/polobymulberry/p/5081049.html 这个非常推荐,博主写了大量的中文注释,基本上把主要的方法都逐个讲解,良心之作

https://www.jianshu.com/p/b98cf91b9ce2

https://www.codercto.com/a/105729.html

基本上是在session的基础上进行了封装,包括各种代理的回调、跟UI的互动、安全性、序列化等,这里主要关注对代理的回调,

第一反应,是http截取的代码与第三方库的代码存在冲突

于是将截取数据模块代码和第三方库(AFNetWork)的代码进行了全盘浏览,发现,两者代码比较相近🧐,事情貌似不简单,初步怀疑是部分代码重复,或者多次hook导致的问题,于是对两者的单例、线程安全、死锁、Hook等地方进行了重点探寻,结果,日子一天一天过,两天后一无所获。。。。。。。

事实上AFNetWork的稳定安全一直比较不错,甚至很多方法都加了sately前缀,比如

     单例、锁、安全前缀一应俱全

    好吧,还是老老实实从复现场景-->锁定代码-->找到问题的顺序一步一步走

   为了好定位,直接将AFNetWork的源码倒入,debug走起

    先用官方request实现一波

一个简单的NSURLSession的request请求,上报情况能够通过回调方法进行展示

在用AFNetwork的方式实现一波

这一次,回调没有反应。现象比较好复现

下一步,定位代码

AFNetwork的代码层数比较多,但核心的方法不多,网上有很多的源码讲解的文章,大家可以参考下

https://www.jianshu.com/p/a360140bf220 ,还有很多分章节分类名进行解析,这里就不一一分享了

,通过get方法回溯,找到AFNetwork对应使用NSURLSession建立连接的地方

这里有个知识点AFURLSessionManager是AFHTTPSessionManager父类,NSURLSession的申请在AFURLSessionManager进行了实现,如下

可以看到AFNetwork也使用了session,只是实现的方式不一样,除了加入默认配置文件,还实现了delegate的方式

调用时datataskwithRequest进行了添加。

那如果直接使用这种方式可以回调吗?

如图:

居然回调不起作用了!

至此,AFNetwork表示,这锅我不背🧐

那目标明确了,就是http截取的业务代码了

一般来说,在控制变量法的原则下,按照先变配置模块、再变初始化模块、接着变主路径、最后变分模块定位的顺序依次排查。

从启动模块开始排查,发现首先进入配置初始化,

打开看下配置内容

看起来就第一个比较可疑

关掉试下

居然成功回调了!

找下allowInterveneNetwork涉及的地方

主要有三个方法

xxx_urlSessionTaskDidStart,xxx_urlSessionTaskDidStop,xxx_sessionWithConfiguration

 通过命名就可以看出来,第一个是task任务开始前,第二个任务是task结束后,第三个任务是进行初始配置

三个方法分别关闭,逐个回调情况

xxx_urlSessionTaskDidStart和xxx_urlSessionTaskDidStop分别关闭时偶尔出现回调,一起关闭时偶尔出现回调

xxx_sessionWithConfiguration关闭时,偶尔出现回调

。。。看来比较玄学。。。问题又一次陷入了僵局

逐个看代码

xxx_sessionWithConfiguration对应的一段代码吸引了我

xxx_sessionWithConfiguration是用来替换系统方法sessionWithConfiguration,这里刚好与前期没有回调的方法匹配

,看来问题大概率就在这里了

xxx_sessionWithConfiguration大概意思是创建了一proxy的实例,将系统原生的delegate进行封装,而后进行传递

,按照控制变量法,将封装去掉,看看回调是否成功

成功了!

看来就是这了

接着看proxy和delegate之间的联系

proxy是nsproxy的子类

通过一个弱引用,引用delegate

这里一个知识点:nsproxy作为代理更为轻量,因为

  • NSProxy是一个抽象的基类,是根类,与NSObject类似
  • NSProxyNSObject都实现了<NSObject>协议

NSObject的所有Category中定义的方法无法在继承NSObject的代理中完成转发,具体参考

http://tanhao.me/code/160702.html/ 这里使用了nsproxy主要在转发时,进行http截取,然后再进行真正的转发

既然做转发,就在每次转发时打印一下log,看看有没有回到原始的delegate

结果比较诧异!

proxy引用的delegate变为空!

怪不得delegate没反应

现在的情况是变成

proxy--->delegate 时 delegate为空

dalagate单独使用,可以正常使用

查看一下proxy里面的代码,确认没有置空的操作

所以问题变成了delegate怎么没的

按照内存爱好者的常用思想,弱引用是否有问题,其实proxy一般来说使用弱引用,这样可以解决一些定时器等循环引用的问题

https://blog.csdn.net/shubinniu/article/details/80895450

问题又一次陷入了僵局

😂

最后,不死心试下将proxy--->delegate 的弱引用变成强引用

成功了!

什么原因呢?

再分析一次

proxy--->delegate 弱引用时 delegate被置空

proxy——>delegate 强引用时 delegate有效,可以正常使用

dalagate单独使用,可以正常使用

proxy里面没有置空delegate的操作

所以,谁置空了delegate!

推理大师说过,除所有不可能的,剩下的那个即使再不可思议,那也是事实

不要怀疑,是的,这是一个系统bug!!!

NSProxy在ARC下,弱引用的属性,会被强制置空,不要怀疑,亲测有效

https://joris.kluivers.nl/blog/2012/03/26/weak-references-to-nsproxy-with-arc/

https://oomake.com/question/2426222

https://stackoverflow.com/questions/9104544/how-can-i-get-ocmock-under-arc-to-stop-nilling-an-nsproxy-subclass-set-using-a-w

大家可以尝试一下,刺激。。。

拓展知识1:

对于http的截取分析,有两个思路,一个是AFNetWork的思路,通过获取代理和HOOK  resume 和suspend的方式,一种是https://www.jianshu.com/p/ae5e8f9988d8的方法,其实两种方式各有利弊,AFN的方法是大部分第三方库的方式,“紧贴”系统方法,与系统交互较多,能够更多的进行性能分析,而后面这种思路“紧贴”业务,可以对前后端的数据进行业务级过滤,重定向等,看具体业务需要

拓展知识2:

关于网络监控ios版,有些比较优秀的可以参考

https://www.jianshu.com/p/3bdb027a63c7

http://code4app.com/blog-822717-1166.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-06-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一反应,是http截取的代码与第三方库的代码存在冲突
  •     好吧,还是老老实实从复现场景-->锁定代码-->找到问题的顺序一步一步走
  • 至此,AFNetwork表示,这锅我不背🧐
  • 一般来说,在控制变量法的原则下,按照先变配置模块、再变初始化模块、接着变主路径、最后变分模块定位的顺序依次排查。
  • 推理大师说过,除所有不可能的,剩下的那个即使再不可思议,那也是事实
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档