iOS之一个popViewControllerAnimated引发的Crash

857 阅读2分钟

今天测试在测试的时候遇到个场景发生了Crash

iOS原生跳转到我们自身小程序,然后小程序点击了一个按钮,然后关闭小程序接着调用原生的一个push到一个ViewController加载webView

iOS原生工作台 -> 小程序SDK -> 小程序组件(点击一个按钮) -> 关闭小程序 -> 回到原生 -> 原生跳转到新的ViewController加载WebView

但就是关闭小程序到原生这个过程,是先popViewControllerAnimated的,然后紧接着传回调,然后回到原生工作台,跳转到对应的组件,但是在这个过程当中,崩溃堆栈可以看到

image.png

首先崩溃的原因是是在dealloc当中写了,这个是小问题,后面改成_webView就好了,但还是有问题

-(void)dealloc{
    [self.webView removeObserver:self forKeyPath:@"123"];
    [self.webView removeObserver:self forKeyPath:@"321"];
    [self.webView removeObserver:self forKeyPath:@"213"];
}

而小程序SDK当中关闭小程序写的代码为

[self.navigationController popViewControllerAnimated:YES];

 ...... 抛出回调是否退出成功

来到原生跳转则是直接创建了一个ViewController

打断点可以确认的是先走了小程序SDK关闭,然后才来到跳转ViewController,那为什么上面堆栈信息先走dealloc,才走webView

反复看了SDK的代码,发现就只有popViewControllerAnimated,然后猜测这句代码可能不是在主线程执行,把代码都包在了主线程块里面,还是一样Crash,但是一旦去掉就是好的,开始查询popViewControllerAnimated的问题

然后自己写了一个Demo来测试,复现上述结果

image.png

image.png

打印结果为:
2021-12-21 18:17:58.203173+0800 test[34801:253086] 213
2021-12-21 18:17:58.204249+0800 test[34801:253086] 我执行完popViewControllerAnimated了
2021-12-21 18:17:58.204348+0800 test[34801:253086] block执行了
2021-12-21 18:17:58.714026+0800 test[34801:253086] 我执行了delloc

搞了一系列骚操作,都能正常跳转,在demo里面复现不出来这个问题,开始看popViewControllerAnimated有没有被重写或者啥的,果然发现popViewControllerAnimated是被method_exchangeImplementations了的

- (UIViewController *)safePopViewControllerAnimated:(BOOL)animated {
    
    if (self.viewTransitionInProgress) return nil;
    if (animated) {
        self.viewTransitionInProgress = YES;
    }
    UIViewController *viewController = [self safePopViewControllerAnimated:animated];
    if (viewController == nil) {
        self.viewTransitionInProgress = NO;
    }
    return viewController;
}

现在问题就很清晰了,是因为防止在转场的过程中跳转,加的保护,而在这边我们跳转从小程序SDK关闭pop然后再push,push并没有成功,VC创建后在作用域结束后就直接dealloc了,所以才会走到dealloc,然后dealloc又去持有了webView,所以造成了这样的问题。