应用程序在 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 initviewDidLoad - 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;
    



HomeGlanceControllerBaseSplitViewController 的子类(它是 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 中崩溃的主要内容,如果未能解决你的问题,请参考以下文章

获取 当前显示的 UIViewController

UISplitViewControllers detailView 中的 presentModalViewController 未全屏显示视图

在 swift 中,如何在应用程序委托中实现一个变量,以便在应用程序的任何地方检索它?

MFP 应用程序在应用程序未运行时在推送通知期间点击时崩溃

在特定时间后终止在后台运行的应用程序?

mac 应用程序安装文件夹在哪