[iOS][兼容性]iOS7 pushViewController,popViewControllerAnimated存在的问题

    xiaoxiao2023-05-26  4

    问题引入

    最近在项目中,遇到一个问题:  实现类似于设置功能的简单应用,方法是中在storyboard中,基于UITableView 建立一个静态tableViewCell。基于这个静态cell直接在storyboard上拖拽到下一级Controller, 方法为push。 问题现象:ios8以上系统没有问题。到ios7系统,出现crash. 最后用下边博文的方法解决。 转载分享给大家,下面是转载原文 : ---------------------------------

    问题:

    iOS7 相比iOS8及以后,在页面进入或者退出的时候,有一定延迟

    比如push到子页面的时候,如果viewwillappear 还没有完成,就直接再进入下一个页面,就会crash

    场景1:

    举例场景:用户查看自己的地址列表时,如果地址列表为空,产品希望我们APP自动跳转到新建地址的页面

    这个常规的做法是在viewdidload里面request address list,在response里面,判断如果空的话,push到新建address的页面

    做出来,iOS8.9都ok,但是在iOS7上就会直接crash

    类似很多场景(push/pop操作未完成,就继续push/pop),如果大家crash,能看到“Can't add self as subview”

    类似这种,就是其中之一的场景。

    解决方案:

    这种的主流解决方案是:在viewwillappear的时候再执行相关动作。

    我这边自己用过的一个方式是使用了个开源库:UIViewController+APSafeTransition

    插一段代码,其实就是建了个父类在所有pop或者push的接口做了统一处理


    问题:

    A->B, Apush 到B,但实际页面还是A,但是导航左上角是个返回按钮(push后自带的返回上一页的backButton),然后整个页面点击无任何响应.

    场景2:

    使用了tabbrviewcontroller, 有4个tab(tabA,tabB .... tabD)

    然后从2个tab,进入了子页面N多层,最后来到页面M,然后点击M页面的提交button后,希望回到第2个界面B。 

    需要达到的效果是,也可能从任何一个tab进入页面M,但都需要进入界面B

    实现方式:

    [self.navigationController popToRootViewControllerAnimated:NO];

    然后发个通知,让tabbarViewController设置select为tabB,然后pushViewController到界面B

    解决方案:

    可能很多童鞋都没看懂,我说了什么,总结下就是popToRootViewController之后,在rooview还没出现viewappear的时候,执行pushViewController,操作,iOS7会出现页面错乱

    但是这个又和上一个问题不太一样,因为之前已经使用了SafeTransition,不应该出这种问题的。

    后来想了下,这个是appdelegate接受Notification 的,而Notification无法保证在主线程(理论上来说,Notification是线程安全的,同时post 和receive是在一个线程里面,但是在这里出了错误,说明的确有问题),于是在pushviewcontroller的地方增加为主线程,于是问题解决。

    备注:这个没有更新完,待补充,具体我需要查看下实际所在的线程,确认在iOS7上的情况,但目前的解决方案是如此。谨记之

    dispatch_async(dispatch_get_main_queue(), ^{

    [currentViewController PushViewController:viewController animation:animation];

    });

    文/pingpong_龘(简书作者) 原文链接:http://www.jianshu.com/p/b49a87093ac4 著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

    源码

    直接将这个分类的源文件,加入项目即可,利用了runtime机制将一部分生命周期函数替换成安全的方式。 // // UINavigationController+APSafeTransition.h // // Created by hanamichi on 16/1/4. // Copyright © 2016年 hanamichi. All rights reserved. // #import <UIKit/UIKit.h> #import <objc/runtime.h> @interface UINavigationController () <UINavigationControllerDelegate> @property (nonatomic, assign) BOOL viewTransitionInProgress; @end @implementation UINavigationController (APSafeTransition) + (void)load { method_exchangeImplementations(class_getInstanceMethod(self, @selector(pushViewController:animated:)), class_getInstanceMethod(self, @selector(safePushViewController:animated:))); method_exchangeImplementations(class_getInstanceMethod(self, @selector(popViewControllerAnimated:)), class_getInstanceMethod(self, @selector(safePopViewControllerAnimated:))); method_exchangeImplementations(class_getInstanceMethod(self, @selector(popToRootViewControllerAnimated:)), class_getInstanceMethod(self, @selector(safePopToRootViewControllerAnimated:))); method_exchangeImplementations(class_getInstanceMethod(self, @selector(popToViewController:animated:)), class_getInstanceMethod(self, @selector(safePopToViewController:animated:))); } #pragma mark - setter & getter - (void)setViewTransitionInProgress:(BOOL)property { NSNumber *number = [NSNumber numberWithBool:property]; objc_setAssociatedObject(self, @selector(viewTransitionInProgress), number, OBJC_ASSOCIATION_RETAIN); } - (BOOL)viewTransitionInProgress { NSNumber *number = objc_getAssociatedObject(self, @selector(viewTransitionInProgress)); return [number boolValue]; } #pragma mark - Intercept Pop, Push, PopToRootVC - (NSArray *)safePopToRootViewControllerAnimated:(BOOL)animated { if (self.viewTransitionInProgress) return nil; if (animated) { self.viewTransitionInProgress = YES; } NSArray *viewControllers = [self safePopToRootViewControllerAnimated:animated]; if (viewControllers.count == 0) { self.viewTransitionInProgress = NO; } return viewControllers; } - (NSArray *)safePopToViewController:(UIViewController *)viewController animated:(BOOL)animated { if (self.viewTransitionInProgress) return nil; if (animated){ self.viewTransitionInProgress = YES; } NSArray *viewControllers = [self safePopToViewController:viewController animated:animated]; if (viewControllers.count == 0) { self.viewTransitionInProgress = NO; } return viewControllers; } - (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; } - (void)safePushViewController:(UIViewController *)viewController animated:(BOOL)animated { if (self.viewTransitionInProgress == NO) { [self safePushViewController:viewController animated:animated]; if (animated) { self.viewTransitionInProgress = YES; } } } @end @implementation UIViewController (APSafeTransitionLock) + (void)load { Method m1; Method m2; m1 = class_getInstanceMethod(self, @selector(sofaViewDidAppear:)); m2 = class_getInstanceMethod(self, @selector(viewDidAppear:)); method_exchangeImplementations(m1, m2); } - (void)sofaViewDidAppear:(BOOL)animated { self.navigationController.viewTransitionInProgress = NO; [self sofaViewDidAppear:animated]; } @end
    转载请注明原文地址: https://ju.6miu.com/read-1260728.html
    最新回复(0)