在UINavigationController中push重复的视图

这个问题是我在上个公司中一个需求引出的问题,我们当时做的是一个商城的APP,购物车需要多处使用,各种商品页、帖子页、订单页等与购物车页面来回的跳转返回,当时为了省事就把购物车页面做成了一个单例页面,不用再需要对商品变动时做过多的处理,只需要管理这一个页面即可。
想法是好的,但是在实际操作的时候出现一个如下问题:

1
Pushing the same view controller instance more than once is not supported (<UIViewController: 0x100203570>)

意思是不可以重复push到一个相同的页面。

解决方案如下:

测试代码下载地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
占位的视图控制器,不做任何实际的展示需要
*/
@interface _AUUPlaceholderViewController: UIViewController
/**
当前占位视图所代表的被重复使用的视图
*/
@property (nonatomic, weak) UIViewController *_associatedReusedPage;
@end
@implementation _AUUPlaceholderViewController
@end
@implementation UINavigationController (AUUNavigator)
+ (void)methodExchangeWithOriginSelector:(SEL)originSelector swizedSelector:(SEL)swizedSelector {
Method originMethod = class_getInstanceMethod([self class], originSelector);
Method swizedMethod = class_getInstanceMethod([self class], swizedSelector);
method_exchangeImplementations(swizedMethod, originMethod);
}
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self methodExchangeWithOriginSelector:@selector(pushViewController:animated:) swizedSelector:@selector(_pushViewController:animated:)];
[self methodExchangeWithOriginSelector:@selector(popViewControllerAnimated:) swizedSelector:@selector(_popViewControllerAnimated:)];
});
}
- (void)_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
// 如果当前的视图栈内包含当前要跳转的视图的话,就使用占位视图占位做替换
if ([self.viewControllers containsObject:viewController]) {
_AUUPlaceholderViewController *tempVC = [[_AUUPlaceholderViewController alloc] init];
tempVC._associatedReusedPage = viewController;
NSMutableArray *viewControllers = [self.viewControllers mutableCopy];
[viewControllers replaceObjectAtIndex:[viewControllers indexOfObject:viewController] withObject:tempVC];
self.viewControllers = viewControllers;
}
[self _pushViewController:viewController animated:animated];
}
- (UIViewController *)_popViewControllerAnimated:(BOOL)animated {
if (self.viewControllers.count >= 2) {
UIViewController *nextPage = [self.viewControllers objectAtIndex:self.viewControllers.count - 2];
// 对返回事件做拦截,如果上个视图是个占位视图,就将其保存的对应视图放在这个位置
if ([nextPage isKindOfClass:[_AUUPlaceholderViewController class]]) {
_AUUPlaceholderViewController *placeholderPage = (_AUUPlaceholderViewController *)nextPage;
NSMutableArray *viewControllers = [self.viewControllers mutableCopy];
[viewControllers replaceObjectAtIndex:viewControllers.count - 2 withObject:placeholderPage._associatedReusedPage];
self.viewControllers = viewControllers;
}
}
return [self _popViewControllerAnimated:animated];
}
@end