应用程序在 UISplitViewController 的 viewWillAppear 中崩溃
Posted
技术标签:
【中文标题】应用程序在 UISplitViewController 的 viewWillAppear 中崩溃【英文标题】:App crashes in viewWillAppear of UISplitViewController 【发布时间】:2014-09-29 16:00:55 【问题描述】:我正在开发一个 ios 应用程序,它使用标签栏在 UISplitViewController 的子类的子类之间进行交换。直到 iOS 8 GM 种子(和发布版本),它运行良好。
但是,当使用 iOS 8 SDK 为运行 iOS 8 的 iPad 构建时,在切换到一个(并且只有一个)视图控制器子类时,我不断遇到崩溃。此崩溃下降到超类 (UISplitViewController) 的 viewWillAppear 方法,并且与在该方法中设置的 Popover 有关:
2014-09-29 09:24:13.526 AppName[51815:2369763] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIPopoverController initWithContentViewController:] must not be called with `nil`.'
*** First throw call stack:
(
0 CoreFoundation 0x0363adf6 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x031fda97 objc_exception_throw + 44
2 CoreFoundation 0x0363ad1d +[NSException raise:format:] + 141
3 UIKit 0x012eaabe -[UIPopoverController _initWithContentViewController:popoverControllerStyle:] + 436
4 UIKit 0x0111eb43 -[UISplitViewController _setupHiddenPopoverControllerWithViewController:] + 122
5 UIKit 0x0111ed82 -[UISplitViewController _viewControllerHiding:] + 322
6 UIKit 0x0112556a -[UISplitViewController viewWillAppear:] + 189
7 AppName 0x001ac9c0 -[BaseSplitViewController viewWillAppear:] + 624
8 AppName 0x00342b82 -[HomeGlanceController viewWillAppear:] + 306
9 UIKit 0x00d7914f -[UIViewController _setViewAppearState:isAnimating:] + 545
10 UIKit 0x00d796ca -[UIViewController __viewWillAppear:] + 148
11 UIKit 0x00d910b1 -[UIViewController(UIContainerViewControllerProtectedMethods) beginAppearanceTransition:animated:] + 200
12 UIKit 0x00dc2dd3 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 619
13 UIKit 0x00dc2352 -[UITabBarController transitionFromViewController:toViewController:] + 64
14 UIKit 0x00dbe545 -[UITabBarController _setSelectedViewController:] + 340
15 UIKit 0x00dbe3c7 -[UITabBarController setSelectedViewController:] + 193
16 UIKit 0x00dc222b -[UITabBarController _tabBarItemClicked:] + 326
17 libobjc.A.dylib 0x032137cd -[NSObject performSelector:withObject:withObject:] + 84
18 UIKit 0x00c1f79d -[UIApplication sendAction:to:from:forEvent:] + 99
19 UIKit 0x00c1f72f -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 64
20 UIKit 0x00f6228d -[UITabBar _sendAction:withEvent:] + 466
21 libobjc.A.dylib 0x032137cd -[NSObject performSelector:withObject:withObject:] + 84
22 UIKit 0x00c1f79d -[UIApplication sendAction:to:from:forEvent:] + 99
23 UIKit 0x00c1f72f -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 64
24 UIKit 0x00d52a16 -[UIControl sendAction:to:forEvent:] + 69
25 UIKit 0x00d52e33 -[UIControl _sendActionsForEvents:withEvent:] + 598
26 UIKit 0x00d52a4e -[UIControl sendActionsForControlEvents:] + 48
27 UIKit 0x00f670b1 -[UITabBar(Static) _buttonUp:] + 123
28 libobjc.A.dylib 0x032137cd -[NSObject performSelector:withObject:withObject:] + 84
29 UIKit 0x00c1f79d -[UIApplication sendAction:to:from:forEvent:] + 99
30 UIKit 0x00c1f72f -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 64
31 UIKit 0x00d52a16 -[UIControl sendAction:to:forEvent:] + 69
32 UIKit 0x00d52e33 -[UIControl _sendActionsForEvents:withEvent:] + 598
33 UIKit 0x00d5209d -[UIControl touchesEnded:withEvent:] + 660
34 UIKit 0x00c6faba -[UIWindow _sendTouchesForEvent:] + 874
35 UIKit 0x00c70595 -[UIWindow sendEvent:] + 791
36 AppName 0x004527b4 -[LHCWindow sendEvent:] + 100
37 UIKit 0x00c35aa9 -[UIApplication sendEvent:] + 242
38 UIKit 0x00c458de _UIApplicationHandleEventFromQueueEvent + 20690
39 UIKit 0x00c1a079 _UIApplicationHandleEventQueue + 2206
40 CoreFoundation 0x0355e7bf __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
41 CoreFoundation 0x035542cd __CFRunLoopDoSources0 + 253
42 CoreFoundation 0x03553828 __CFRunLoopRun + 952
43 CoreFoundation 0x035531ab CFRunLoopRunSpecific + 443
44 CoreFoundation 0x03552fdb CFRunLoopRunInMode + 123
45 GraphicsServices 0x0567524f GSEventRunModal + 192
46 GraphicsServices 0x0567508c GSEventRun + 104
47 UIKit 0x00c1de16 UIApplicationMain + 1526
48 AppName 0x0004c3de main + 222
49 libdyld.dylib 0x03b09ac9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
我发现有问题的 ViewController 在第一次显示时具有三个子视图,但是当我删除共享框架的两个子视图中的任何一个(通过删除 self.view addSubview
调用)时,崩溃仍然存在:
UIImageView, 50, 10, 260, 490
UIView, 50, 10, 260, 490
UIView, 50, 510, 670, 390
什么会导致 UISplitViewController 的子类中与弹出框相关的崩溃?
这是BaseSplitViewController
中的viewWillAppear:
。运行异常断点在[super viewWillAppear:animated]
行停止。
- (void)viewWillAppear:(BOOL)animated
iPadAppDelegate *appDelegate_iPad = [Utils getAppDelegateForDeviceType:DEVICE_TYPE_IPAD];
if(![appDelegate_iPad getIsTabInitialised])
return ;
DDLogVerbose(@"%@ appearing",[self class]);
// Which tab is opening? Log it!
NSString *screen = [kAnalyticsNavigationPrefix stringByAppendingString:NSStringFromClass([self class])];
[AnalyticsManager logEvent:screen];
// Ensure we don't cover anything with the status bar in iOS 7. It looks like
// the orientation code wasn't being called anymore?
[self adjustControllerForOrientation:[self interfaceOrientation]];
[super viewWillAppear:animated];
BaseSplitViewController init
和 viewDidLoad
- awakeFromNib
未被覆盖。
- (id)init
if (self = [super init])
[self setInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation];
return self;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
[super viewDidLoad];
DDLogVerbose(@"%@ loaded",[self class]);
isModalViewPresent = NO;
self.view.backgroundColor = [UIColor whiteColor];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
self.edgesForExtendedLayout = UIRectEdgeNone;
HomeGlanceController
是 BaseSplitViewController
的子类(它是 UISplitViewController 的子类)。它是唯一崩溃的 BSVC 子类。
- (id)init
if (self = [super init])
bIsAnyKeypadPresent = FALSE;
//to create the favorite zone screen view
favoriteScreenBackGroundView = [[UIView alloc] initWithFrame:CGRectMake(280, 0, 720, 430)];
favoriteScreenbackGroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(40, 5, 667,405)];
favoriteZoneScreenMainView = [[UIView alloc] initWithFrame:CGRectMake(20, 40 ,640,340)];
favoriteKeypadScreenMainView = [[UIView alloc] initWithFrame:CGRectMake(10, 50 ,200,330)];
// Initialize the layout for the Favorite Controller.
[self initFavoriteLayoutCoordinates];
UITabBarItem * tabBarItem = [[UITabBarItem alloc]initWithTitle:HomeGlanceTabTitle
image:[Utils getImageNamed:HomeGlanceIcon]
tag:1];
tabBarItem.selectedImage = [Utils getImageNamed:HomeGlanceSelectedIcon];
self.tabBarItem = tabBarItem;
tabBarItem = nil;
// pick the co-ordinates of the favorite view from the layout array.
if ([favControlCoordinatesArray count]>layoutID)
[self setControllerCoordinates:[favControlCoordinatesArray objectAtIndex:layoutID]];
return self;
- (void) viewDidLoad
// I've tried commenting all but the super call out. The crash remains
[self createImageViewForFavorites];
// to create the View for favorite zone
[self createBackGroundViewForFavoriteZoneScreen];
[self createFavoriteZoneScreenToolbar];
[self createFavoriteZoneScreenMainView];
[self createFavoriteKeypadScreenToolbar];
[super viewDidLoad];
- (void)viewWillAppear : (BOOL) animated
[super viewWillAppear:animated];
[self startTimer];
iPadAppDelegate *appDelegate_iPad = [Utils getAppDelegateForDeviceType:DEVICE_TYPE_IPAD];
if(![appDelegate_iPad getIsTabInitialised])
return;
[self createFavoriteZoneScreenMainView];
[self createFavoriteKeypadScreenMainView];
// Snipped methods that don't impact the UI directly (commented out in this build)
显然,只有当 iPad 处于(或转向)纵向模式时才会发生崩溃:
可以选择选项卡而不会在横向崩溃,但在该选项卡上旋转到纵向会在super willRotateToInterfaceOrientation:duration:
崩溃。
如果在纵向选择选项卡,应用程序将在super viewWillAppear:
上崩溃
最终原因似乎是相同的([UIPopoverController initWithContentViewController:] 不得使用nil
调用。)。
【问题讨论】:
发布导致这种情况的代码(BaseSplitViewController
's -(void)viewWillAppear
我想)。此外,为了更好地调试您的异常,您可以添加一个 Objective-C 异常断点as explained here。这会让你知道导致崩溃的确切行。
@RicardoSánchez-Sáez 添加了该方法,尽管我没有看到任何似乎直接相关的内容。我正在运行我的异常断点,它在 super viewWillAppear:
调用上失败 - 忘了提,谢谢提醒我。
您能否尝试将[super viewWillAppear:animated]
调用移至所有viewWillAppear
方法的第一行?
@RicardoSánchez-Sáez 刚刚尝试过,但它仍然崩溃。我尝试删除和重建,但没有效果。这似乎表明它是在 viewLoad 或 init 中处理的,对吧?
你的代码中的popover是如何参与的? BaseSplitViewController
在任何地方都使用弹出框吗?
【参考方案1】:
默认的preferredDisplayMode
似乎是UISplitViewControllerDisplayModeAutomatic
,并且UISplitViewController 正在做一些 涉及在具有该显示模式并调用viewWillAppear
或旋转时以纵向创建弹出框控制器。
为避免崩溃,我在viewDidLoad
方法中添加了更改显示模式的代码:
[self setPreferredDisplayMode:UISplitViewControllerDisplayModeAllVisible];
【讨论】:
以上是关于应用程序在 UISplitViewController 的 viewWillAppear 中崩溃的主要内容,如果未能解决你的问题,请参考以下文章
UISplitViewControllers detailView 中的 presentModalViewController 未全屏显示视图