RTRootNavigationController
RTRootNavigationController copied to clipboard
crash & 一点小建议
在push vc的时候crash 堆栈如下,初步发现只在特定的系统ios 10.1.1,自己用相同的系统无法重现,RTContainerNavigationController - viewDidLoad - [self.view layoutIfNeeded]; 崩在这一行了,请问下这里为什么需要手动调用一下layout,去掉后发现横竖屏切换UI异常,是这个原因么,麻烦解答下,3Q。
还有个小问题,在rootnavigationcontroller 中
- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers
animated:(BOOL)animated
中如何设置的是原先就在栈中的vc会重新wrap一遍,导致之前设置的导航栏效果失效(会被重新初始化一遍),改进如下
//fix 如果在栈中已存在的vc 则直接使用原有的container 不重新封装一层
NSArray *currentVCArr = self.rt_viewControllers;
NSMutableArray *replaceVCArr = [NSMutableArray array];
for (int i = 0; i < viewControllers.count ; i++) {
UIViewController *subVC = [viewControllers objectAtIndex:i];
if([currentVCArr containsObject:subVC]){
NSUInteger index = [currentVCArr indexOfObject:subVC];
UIViewController *orginalContainerVC = [self.viewControllers objectAtIndex:index];
[replaceVCArr addObject:orginalContainerVC];
}else{
[replaceVCArr addObject:subVC];
}
}
下面使用replaceVCArr 即可,可以考虑改进下。
Thread 0 Crashed:
0 libobjc.A.dylib 0x00000001824bef30 objc_msgSend + 16
1 OpenGLES 0x0000000186090830 +[EAGLContext setCurrentContext:] + 108
2 CoreImage 0x0000000187764714 __is_gpu_A9_or_higher_block_invoke + 188
3 libdispatch.dylib 0x00000001828fd1c0 _dispatch_client_callout + 16
4 libdispatch.dylib 0x00000001828fdfb4 dispatch_once_f + 56
5 CoreImage 0x0000000187764650 is_gpu_A9_or_higher + 56
6 CoreImage 0x000000018774337c CI::GLContext::surface_rowbytes_alignment_for_input+ 336764 (CI::PixelFormat) const + 12
7 CoreImage 0x0000000187732558 CI::SurfaceNode::surfaceForROI+ 267608 (CI::Context const*, CGRect) const + 124
8 CoreImage 0x0000000187747958 CI::Context::bind_sampler+ 354648 (CI::TextureSampler const*, CGRect const&, int, CI::KernelArgumentType) + 804
9 CoreImage 0x0000000187744c64 CI::GLContext::bind_arguments+ 343140 (CI::ProgramNode const*, CGRect const&) + 340
10 CoreImage 0x00000001877452a4 CI::GLContext::render_intermediate_node(CI::ProgramNode*, CGRect const&, CI::intermediate_t*, void + 344740 () block_pointer) + 520
11 CoreImage 0x00000001877473bc CI::Context::recursive_render+ 353212 (CI::Node*, CGRect const&, CI::Node*) + 800
12 CoreImage 0x000000018774725c CI::Context::recursive_render+ 352860 (CI::Node*, CGRect const&, CI::Node*) + 448
13 CoreImage 0x000000018774725c CI::Context::recursive_render+ 352860 (CI::Node*, CGRect const&, CI::Node*) + 448
14 CoreImage 0x0000000187747618 CI::Context::render+ 353816 (CI::Node*, CGRect const&) + 88
15 CoreImage 0x0000000187758e30 invocation function for block in CI::image_get_bitmap+ 425520 (CI::Context*, CI::Image*, CGRect, CGColorSpace*, CI::Bitmap*) + 544
16 CoreImage 0x000000018775879c CI::tile_node_graph(CI::Context*, char const*, CI::Node*, CGRect const&, CI::PixelFormat, CI::swizzle_info const&, void + 423836 (CI::Node*, CGRect) block_pointer) + 484
17 CoreImage 0x0000000187757268 CI::image_get_bitmap+ 418408 (CI::Context*, CI::Image*, CGRect, CGColorSpace*, CI::Bitmap*) + 948
18 CoreImage 0x000000018771782c -[CIContext render:toBitmap:rowBytes:bounds:format:colorSpace:] + 768
19 CoreUI 0x00000001897074c0 -[CUIShapeEffectStack newFlattenedImageFromShapeCGImage:withScale:ciContext:] + 396
20 CoreUI 0x000000018970e474 -[CUICatalog imageByStylingImage:stylePresetName:styleConfiguration:foregroundColor:scale:] + 116
21 UIKit 0x0000000189b937d4 -[UIImage _imageWithStylePresets:withTintColor:] + 628
22 UIKit 0x00000001898dbbf0 -[UIImageView _setImageViewContents:] + 1368
23 UIKit 0x00000001898db214 -[UIImageView _updateState] + 644
24 UIKit 0x00000001898daf68 +[UIView+ 122728 (Animation) performWithoutAnimation:] + 104
25 UIKit 0x0000000189c68a44 -[UIImageView _updateImageViewForOldImage:newImage:] + 632
26 UIKit 0x00000001898da8d4 -[UIImageView setImage:] + 352
27 UIKit 0x0000000189dc27b0 -[UIButton _updateImageView] + 176
28 UIKit 0x0000000189922674 -[UIButton layoutSubviews] + 192
29 UIKit 0x00000001898ca220 -[UIView+ 53792 (CALayerDelegate) layoutSublayersOfLayer:] + 1196
30 QuartzCore 0x0000000186d8a188 -[CALayer layoutSublayers] + 148
31 QuartzCore 0x0000000186d7ee64 CA::Layer::layout_if_needed+ 1093220 (CA::Transaction*) + 292
32 UIKit 0x00000001898dec90 -[UIView+ 138384 (Hierarchy) layoutBelowIfNeeded] + 1020
33 bigoshow 0x00000001000550a8 -[RTContainerNavigationController viewDidLoad] + 118952 (BVRootNavigationController.m:394)
34 UIKit 0x00000001898cd0b0 -[UIViewController loadViewIfRequired] + 1056
35 UIKit 0x00000001898ccc78 -[UIViewController view] + 28
36 bigoshow 0x0000000100053cb0 -[RTContainerController viewDidLoad] + 113840 (BVRootNavigationController.m:226)
37 UIKit 0x00000001898cd0b0 -[UIViewController loadViewIfRequired] + 1056
38 UIKit 0x00000001898ccc78 -[UIViewController view] + 28
39 bigoshow 0x000000010005813c -[BVRootNavigationController setGestureRecognizerWithViewController:] + 131388 (BVRootNavigationController.m:945)
40 bigoshow 0x0000000100057fd4 -[BVRootNavigationController pushViewController:animated:] + 131028 (BVRootNavigationController.m:924)
41 bigoshow 0x00000001000556bc -[RTContainerNavigationController pushViewController:animated:] + 120508
这个 crash 貌似是你自己的业务代码产生的,查看下 opengl 相关的使用?
setViewControllers:animated: 确实是用法不好理解
- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers
animated:(BOOL)animated
{
[super setViewControllers:[viewControllers rt_map:^id(__kindof UIViewController * obj, NSUInteger index) {
if (self.useSystemBackBarButtonItem && index > 0) {
return RTSafeWrapViewController(obj,
obj.rt_navigationBarClass,
self.useSystemBackBarButtonItem,
viewControllers[index - 1].navigationItem.backBarButtonItem,
viewControllers[index - 1].title);
}
else
return RTSafeWrapViewController(obj, obj.rt_navigationBarClass);
}]
animated:animated];
}
原代码是 RTSafeWrapViewController,所以参数 viewControllers 应当通过 self.rt_navigationController.viewControllers 获取,而不是 self.rt_navigationController.rt_viewControllers 获取,这样就不会有问题
不重新 wrap 会产生新问题,返回按钮上的字会不正确,如栈中已经有: VC1 => title1 VC2 => title2 VC3 => title3
然后 [self.navigationController setViewControllers:@[VC1, VC3] animated:YES],这时 VC3 上的返回按钮可能还是 title2,但应该是 title1 了(在 useSystemBackBarButtonItem = YES 的情况下)
因为在日常使用过程中,需要对堆栈的vc做出处理,比如需要找到某个特定的vc,然后移除之后添加下一个vc。 前:[vc3,vc2,vc1] 后:[vc4,vc2,vc1] --- 这里的vc都是没有wrap的。 如果使用 self.rt_navigationController.viewControllers 来获取,则需要在拿一下contentViewcontroller(方便判断class类型),对于使用者来说不符合预期。
我加的那个判断就是防止这种情况(因为你无法强调使用者在setviewcontrollers中传的到底是什么类型),因为这个数组中完全有可能是掺杂着wrap过和没有wrap的。在传入的是unwrap后的vc,而且这个vc本身已经存在在viewcontrollers中,则手动把它替换成wrap后的(防止被重新wrap),我觉得这种操作是对使用者友好的。
如果每次都重新wrap,那么在set的时候就会把vc1重新wrap一下,比如我在vc1的viewdidload中有做一些对导航栏的初始化操作,那么就不会执行了(因为重新wrap并不会重新viewdidload,这是显然也符合预期的)。
还有一点是我并没有使用这个api相关导航栏的操作,我是自己封装的,使用这个框架最想解决的问题是每个vc独立的navbar。所以楼主提到的返回title问题可能没有了解过。
至于那个崩溃确实也是比较奇怪,因为单纯的 [EAGLContext setCurrentContext:] 崩溃在这一行确实让人找不到原因,这里问一下主要目的可能是想问一下作者的产品是否有类似的问题,所以提出来了。(之前的版本是没有这个崩溃的)。
最后还有一个问题是,RTContainerNavigationController 中是否做一下presentViewController,dismissViewControllerAnimated的消息转发,因为在日常使用过程中会出现present 一个 rtrootnavvc的情况,但是在dismiss调用的是否我们往往的self.navigationController dismiss...,这也是pushvc转发的原因吧。如果使用者重写了dismiss,并在其中做了某些处理,直接通过[self.navigationController dismiss...]则并不会调用到rootnavvc的dismiss了。
返回的 title 修改应该可以不重新 wrap 实现,这个问题后面有空再看。
dismiss 的问题你其实可以直接 [self dismissViewController...],不过也算个问题
有空帮助测试下分支 https://github.com/rickytan/RTRootNavigationController/tree/issue158 有没有解决你的问题
上面说的崩溃解决了吗?怎么解决的可以说以一下吗?谢谢