phone - iOS app error - Can't add self as subview - Stack Overflow

同一时间同时push多个controller在返回的时候会爆这样的错误,其本质的根源是push动画没有完成你就急着去push下一个controller。

解决的办法如下:

通过创建一个导航控制器的分类,将原有的push方法覆盖,再重写load方法,在里面exchange新的push和原始的push

iphone - iOS app error - Can't add self as subview - Stack Overflow

#import "UINavigationController+Consistent.h"

#import

/// This char is used to add storage for the

isPushingViewController property.

staticcharconst*constObjectTagKey="ObjectTag";

@interfaceUINavigationController()

@property(readwrite,getter = isViewTransitionInProgress) BOOL

viewTransitionInProgress;

@end

@implementationUINavigationController(Consistent)

-(void)setViewTransitionInProgress:(BOOL)property {

NSNumber *number = [NSNumbernumberWithBool:property];

objc_setAssociatedObject(self,ObjectTagKey, number , OBJC_ASSOCIATION_RETAIN);

}

-(BOOL)isViewTransitionInProgress {

NSNumber *number =objc_getAssociatedObject(self, ObjectTagKey);

return[number boolValue];

}

//注意上面是设置对象关联

#pragmamark -InterceptPop,Push,PopToRootVC

/// @name Intercept Pop, Push, PopToRootVC

- (NSArray*)safePopToRootViewControllerAnimated:(BOOL)animated{

if(self.viewTransitionInProgress)returnnil;

if(animated){

self.viewTransitionInProgress =YES;

}

//-- This is not a recursion, due to method swizzling thecall below calls the originalmethod.

return[self

safePopToRootViewControllerAnimated:animated];

}

- (NSArray*)safePopToViewController:(UIViewController*)viewController animated:(BOOL)animated {

if(self.viewTransitionInProgress)returnnil;

if(animated){

self.viewTransitionInProgress =YES;

}

//-- This is not a recursion, due to method swizzling thecall below calls the originalmethod.

return[selfsafePopToViewController:viewController animated:animated];

}

- (UIViewController*)safePopViewControllerAnimated:(BOOL)animated{

if(self.viewTransitionInProgress)returnnil;

if(animated){

self.viewTransitionInProgress =YES;

}

return[selfsafePopViewControllerAnimated:animated];

}

- (void)safePushViewController:(UIViewController*)viewController animated:(BOOL)animated {

self.delegate=self;

//-- If we are already pushing a view controller, we dont

push another one.

if(self.isViewTransitionInProgress == NO) {

//-- This is not a recursion, due to method swizzling thecall below calls the originalmethod.

[selfsafePushViewController:viewController animated:animated];

if(animated){

self.viewTransitionInProgress = YES;

}

}

}

// This is confirmed to be App Store safe.

// If you feel

uncomfortable to use Private API, you could also use the delegate method

navigationController:didShowViewController:animated:.

- (void)safeDidShowViewController:(UIViewController*)viewController animated:(BOOL)animated {

//-- This is not a recursion. Due to method swizzling this

is calling the original method.

[selfsafeDidShowViewController:viewController animated:animated];

self.viewTransitionInProgress =NO;

}

// If the user doesnt complete the swipe-to-go-back gesture,

we need to intercept it and set the flag to NO again.

- (void)navigationController:(UINavigationController*)navigationController willShowViewController:(UIViewController*)viewController animated:(BOOL)animated {

id tc =navigationController.topViewController.transitionCoordinator;

[tcnotifyWhenInteractionEndsUsingBlock:^(id context) {

self.viewTransitionInProgress =NO;

//--Reenable swipe back gesture.

self.interactivePopGestureRecognizer.delegate= (id)viewController;

[self.interactivePopGestureRecognizer setEnabled:YES];

}];

//-- Method swizzling wont work in the case of a delegate

so:

//-- forward this method to the original delegate if there

is one different than ourselves.

if(navigationController.delegate!= self) {

[navigationController.delegatenavigationController:navigationController

willShowViewController:viewController

animated:animated];

}

}

+ (void)load {

//-- Exchange the original implementation with our custom

one.

method_exchangeImplementations(class_getInstanceMethod(self,@selector(pushViewController:animated:)),

class_getInstanceMethod(self,@selector(safePushViewController:animated:)));

method_exchangeImplementations(class_getInstanceMethod(self,@selector(didShowViewController:animated:)),

class_getInstanceMethod(self,@selector(safeDidShowViewController: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:)));

}

@end

//+ (void)load在类被加载的时候就会被执行,所以即使没有引入头文件或者主动调用他也会被执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值