开发进阶 Runtime

Runtime の滥用典型

2016-08-17  本文已影响21人  Ever_Blacks

不要滥用Runtime !!!
不要滥用Runtime !!!
不要滥用Runtime !!!

重要的事说三遍😂。

先上Bug截图

Bug.PNG

昨天快下班的时候,老大突然走过来给我演示了这个Bug。当时我是震惊的因为这个页面是Webview, 而且只是简单的load一个URL甚至连webview的delegate都没有设置。再三向后台同学确认没有在这个页面做任何弹出框之后,我开始思索这个弹出框到底是什么?


Why.png

经过一番探索之后,因为这个页面调用的百度地图的Javascript API 获取Location, 弹出框是来获取Location的权限的。

大家都知道AlertView当没有Title或者Message的时候才会出现Bug截图出现的这种情况,可这明显的系统弹框Title或者Message哪去了呢???

我做了以下的尝试:

  1. 把这个页面的URL发到QQ和微信然后在打开链接 结果是可以正常显示弹出框
  2. 把链接复制到Safari中,打开网页正常显示弹出框
  3. 把当前的UIWebView 替换成iOS 8 之后才有的 WKWebView 结果依旧不能出现Title
  4. 新建一个空工程, 在空工程中加载这个页面,结果不论是UIWebView 或者 WKWebView都能正常显示弹出框

经过以上的探索,已经可以确认问题出现在我的工程的代码中。因为已经在Info.plist中添加NSLocationAlwaysUsageDescription并且用原生的代码可以获取到Location,所以可以排除App的设置问题。

用尽了各种办法依旧无法确定问题的时候,突然想到了一个或许可行的办法--既然是弹出框,那么如果我用Runtime的方法替换掉alertView的show方法是不是可以断点到出问题的代码呢? 然后就有了以下的Debug代码

+ (void)load
{
    Method myshow = class_getInstanceMethod([self class], @selector(myshow));
    Method show = class_getInstanceMethod([self class], @selector(show));
    
    method_exchangeImplementations(show, myshow);
}

- (void)myshow
{
    MyLog(@"self.title: %@", self.title);
    MyLog(@"self.message: %@", self.message);
    [self myshow];
}

结果证明我的思路是正确的,成功执行了代码并且打印的title和message都和预料的一样为空。问题现在也就变成了为啥系统的弹出框会没有Title呢❓❓❓

经过一点点的查看断点堆栈终于找到了问题的源头--一个ViewController的方法替换😂

//避免使用setTitle 引起Navi bar item 名称改变
swizzInstance([self class], @selector(setTitle:), @selector(swizzSetTitle:)); 

- (void)swizzSetTitle:(NSString *)title
{    
        self.navigationItem.title = title;
}

因为App的主体结构使用了CYLTabBarController这个框架,为了避免在设置ViewController的时候更改Title引起Tabbar Item title的改变,所以必须使用self.navigationItem.title = title;这种设置方法。 为了偷懒就用“万恶”的Runtime替换了viewController的setTitle: 方法。

但是因为iOS8之后,增加的UIAlertController继承于UIViewController, 所以UIAlertController的setTitle方法也莫名躺枪了😂就造成了此处的bug。

最后附上解决之后的截图

IMG_0987.PNG
上一篇下一篇

猜你喜欢

热点阅读