iPhone 4 和 iPhone 5 的单独故事板仅在模拟器中导致崩溃

Posted

技术标签:

【中文标题】iPhone 4 和 iPhone 5 的单独故事板仅在模拟器中导致崩溃【英文标题】:Separate Storyboards for iPhone 4 and iPhone 5 Cause Crash in Simulator Only 【发布时间】:2014-06-26 04:11:49 【问题描述】:

我的项目中设置了 2 个故事板,一个用于 iPhone 4,一个用于 iPhone 5。

我在 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 中设置了切换情节提要的代码,如下所示:

  CGSize iosDeviceScreenSize = [[UIScreen mainScreen] bounds].size;

    if (iOSDeviceScreenSize.height == 480)
    
        // Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone4
        UIStoryboard *Storyboard_iPhone4 = [UIStoryboard storyboardWithName:@"Storyboard_iPhone4" bundle:nil];

        // Instantiate the initial view controller object from the storyboard
        UIViewController *initialViewController = [Storyboard_iPhone4 instantiateInitialViewController];

        // Instantiate a UIWindow object and initialize it with the screen size of the iOS device
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

        // Set the initial view controller to be the root view controller of the window object
        self.window.rootViewController  = initialViewController;

        // Set the window object to be the key window and show it
        [self.window makeKeyAndVisible];
    

    if (iOSDeviceScreenSize.height >= 568)
       // iPhone 5 and iPod Touch 5th generation: 4 inch screen
        // Instantiate a new storyboard object using the storyboard file named Main
        UIStoryboard *Main2 = [UIStoryboard storyboardWithName:@"Main2" bundle:nil];

        UIViewController *initialViewController = [Main2 instantiateInitialViewController];
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        self.window.rootViewController  = initialViewController;
        [self.window makeKeyAndVisible];
    
    else
    
        UIStoryboard *Main2 = [UIStoryboard storyboardWithName:@"Main2" bundle:nil];
        UIViewController *initialViewController = [Main2 instantiateInitialViewController];
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        self.window.rootViewController  = initialViewController;
        [self.window makeKeyAndVisible];
    

仅在模拟器上运行时我会收到以下错误(iPhone 4 和 iPhone 5 设备可以正常工作并按预期切换情节提要):

线程 1:EXC_BAD_ACCESS(代码=2,地址=0xc)

这发生在这里:

int main(int argc, char * argv[])

    @autoreleasepool 
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    

我目前在 Xcode 5 中工作。

这是跟踪(不确定我是否正确):

libobjc.A.dylib`objc_msgSend:
0x260e0a4:  movl   0x8(%esp), %ecx
0x260e0a8:  movl   0x4(%esp), %eax
0x260e0ac:  testl  %eax, %eax
0x260e0ae:  je     0x260e110                 ; objc_msgSend + 108
0x260e0b0:  movl   (%eax), %edx
0x260e0b2:  movzwl 0xc(%edx), %eax
0x260e0b6:  andl   %ecx, %eax
0x260e0b8:  shll   $0x3, %eax
0x260e0bb:  addl   0x8(%edx), %eax
0x260e0be:  cmpl   (%eax), %ecx
0x260e0c0:  jne    0x260e0c5                 ; objc_msgSend + 33
0x260e0c2:  jmpl   *0x4(%eax)
0x260e0c5:  cmpl   $0x0, (%eax)
0x260e0c8:  je     0x260e119                 ; objc_msgSend + 117
0x260e0ca:  cmpl   0x8(%edx), %eax
0x260e0cd:  je     0x260e0d9                 ; objc_msgSend + 53
0x260e0cf:  subl   $0x8, %eax
0x260e0d2:  cmpl   (%eax), %ecx
0x260e0d4:  jne    0x260e0c5                 ; objc_msgSend + 33
0x260e0d6:  jmpl   *0x4(%eax)
0x260e0d9:  movzwl 0xc(%edx), %eax
0x260e0dd:  shll   $0x3, %eax
0x260e0e0:  addl   0x8(%edx), %eax
0x260e0e3:  jmp    0x260e0f2                 ; objc_msgSend + 78
0x260e0e5:  cmpl   $0x0, (%eax)
0x260e0e8:  je     0x260e119                 ; objc_msgSend + 117
0x260e0ea:  cmpl   0x8(%edx), %eax
0x260e0ed:  je     0x260e0f9                 ; objc_msgSend + 85
0x260e0ef:  subl   $0x8, %eax
0x260e0f2:  cmpl   (%eax), %ecx
0x260e0f4:  jne    0x260e0e5                 ; objc_msgSend + 65
0x260e0f6:  jmpl   *0x4(%eax)
0x260e0f9:  pushl  %ebp
0x260e0fa:  movl   %esp, %ebp
0x260e0fc:  pushl  $0x0
0x260e0fe:  pushl  $0x0
0x260e100:  pushl  $0x0
0x260e102:  pushl  %edx
0x260e103:  pushl  %ecx
0x260e104:  movl   0x8(%ebp), %ecx
0x260e107:  pushl  %ecx
0x260e108:  calll  0x25fc720                 ; objc_msgSend_corrupt_cache_error
0x260e10d:  nopl   (%eax)
0x260e110:  xorl   %edx, %edx
0x260e112:  xorps  %xmm0, %xmm0
0x260e115:  xorps  %xmm1, %xmm1
0x260e118:  ret    
0x260e119:  movl   0x8(%esp), %ecx
0x260e11d:  movl   0x4(%esp), %eax
0x260e121:  pushl  %ebp
0x260e122:  movl   %esp, %ebp
0x260e124:  subl   $0xc, %esp
0x260e127:  pushl  %edx
0x260e128:  pushl  %ecx
0x260e129:  pushl  %eax
0x260e12a:  calll  0x260606f                 ; _class_lookupMethodAndLoadCache3
0x260e12f:  leave  
0x260e130:  cmpl   %eax, %eax
0x260e132:  jmpl   *%eax

【问题讨论】:

设置异常断点(视图 -> 导航器 -> 断点导航器,或命令 7)。重新运行以获得崩溃的完整堆栈跟踪,以便我们知道崩溃发生的位置。 另外 EXC_BAD_ACCESS 通常是内存问题。开启僵尸对象可以帮到你developer.apple.com/library/ios/recipes/… @BrandonRoth 添加了跟踪,不确定我是否正确。 不完全是,那是被调用的汇编代码。你想要的是一个异常断点以及启用的僵尸对象,这样我们就可以在它冒泡到你的主函数***.com/questions/4961770/…之前看到崩溃。 @BrandonRoth 感谢您的回复,我启用了僵尸对象和异常断点。它带我回到我复制并粘贴上述代码的窗口。以下是我看到的是否有帮助:http://i.imgur.com/PaiNdN7.png 【参考方案1】:

因此,根据控制台的图像,崩溃是因为一条消息被发送到一个已释放的实例。你可以从右边看到 lldb() 它说 [_UIDelayedPresentationContext delayingController] 消息发送到释放的实例

我想知道这在模拟器中会在哪些设备上崩溃 - 它会在 3.5 英寸和 4 英寸设备上崩溃吗?

我突然想到的一件事是,您的第一个 if 语句启动了从 Storyboard_iPhone4 故事板创建 UIWindow 和 UINavigationController 的过程。然后紧接着你有一个 if-else 做完全相同的事情,但来自不同的故事板。因此,如果设备不是 4 英寸设备,您最终会创建两次窗口,我想知道这是否是崩溃的根源。如果删除第一个 if 语句会改变事情吗?

【讨论】:

设备会导致 3.5 和 4 英寸模拟设备崩溃。我删除了 if-else,但仍然收到错误消息。 我也能找到这些附加信息:http://i.imgur.com/iFC0eWJ.png 您是否在其中一个视图控制器中使用了 gameCenter?根据仪器跟踪,这可能与超级烦人的游戏中心登录有关,有时需要 FOREVER 才能显示? 是的,我注意到这发生在加载 Game Center 屏幕时。模拟器锁定变得无响应。 你是否在项目文件中也设置了故事板,在目标下?如果是这样,故事板、窗口和视图控制器也会在您进入应用程序委托并做自己的事情之前被加载。尝试删除它以使自己减少到 1 个窗口并查看控制器实例化。

以上是关于iPhone 4 和 iPhone 5 的单独故事板仅在模拟器中导致崩溃的主要内容,如果未能解决你的问题,请参考以下文章

一个适用于 iPhone 3.5 和 4 英寸的故事板

我们是不是需要为所有 iPhone/iPad 设备提供单独的故事板?

故事板转场覆盖 iPhone 4 和 5 上的垂直过渡

我可以为 iPhone 和 iPad(纵向和横向)使用单独的故事板吗?

如何在不为 iphone 和 ipad 创建单独的 xib 的情况下为所有 ipad 和 iphone 创建通用 xib?不是故事板

故事板视图(iphone 4/5/6)影响集合单元大小的布局(以编程方式设置)