Reputation: 12241
I'm working on an iOS app that uses a tab bar to swap between subclasses of a subclass of UISplitViewController. Up until the iOS 8 GM seed (and release version), that was working fine.
However, when building with the iOS 8 SDK for an iPad running iOS 8, I am continually getting a crash when switching to one (and only one) of the view controller subclasses. This crash drops down into the viewWillAppear method of the superclass (UISplitViewController), and has something to do with a Popover being set up in that method:
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
I found that the ViewController in question has three subviews the first time it is shown, but when I remove either of the two that share a frame (by removing the self.view addSubview
calls) the crash is still there:
UIImageView, {{50, 10}, {260, 490}}
UIView, {{50, 10}, {260, 490}}
UIView, {{50, 510}, {670, 390}}
What would cause a popover related crash in a subclass of UISplitViewController?
This is the viewWillAppear:
in the BaseSplitViewController
. Running an exception breakpoint stops on the [super viewWillAppear:animated]
line.
- (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];
}
The BaseSplitViewController init
and viewDidLoad
- awakeFromNib
is not overriden.
- (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
subclasses BaseSplitViewController
(which subclasses the UISplitViewController). It is the only subclass of BSVC that crashes.
- (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)
}
Apparently the crash only occurs when the iPad is in (or turned to) portrait mode:
super willRotateToInterfaceOrientation:duration:
.super viewWillAppear:
The end cause appears to be the same ([UIPopoverController initWithContentViewController:] must not be called with nil
.).
Upvotes: 0
Views: 1551
Reputation: 12241
It appears the default preferredDisplayMode
is UISplitViewControllerDisplayModeAutomatic
, and the UISplitViewController is doing something involving creating a popover controller in portrait when it has that display mode and it calls viewWillAppear
or rotates.
To avoid the crash, I added code to change the display mode in the viewDidLoad
method:
[self setPreferredDisplayMode:UISplitViewControllerDisplayModeAllVisible];
Upvotes: 4