使用Blocks会在iPhone模拟器4.3/XCode 4.2和4.0.2中崩溃应用程序

Dav*_*sey 7 xcode objective-c ios objective-c-blocks ios-simulator

还有其他人在XCode 4.2(Lion)或4.0.2中遇到4.3 iPhone模拟器的问题吗?

我的代码长期以来一直在工作,测试和生产中使用块来指定完成操作.例如,我使用UIView动画来淡出标签顶部的一些文本,如下所示:

[UIView animateWithDuration: 0.0 
                      delay: 0.0 
                    options: (UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionNone)
                 animations: ^{

                     videoTextLabel1.alpha = 0.0;
                     videoTextLabel2.alpha = 0.0;
                     videoTextLabel3.alpha = 0.0;
                 }

                 completion: ^(BOOL completed) {
                     [self fadeInNextMeditationLine: 0];
                 }];
Run Code Online (Sandbox Code Playgroud)

我可靠地在模拟器中获得EXEC_BAD_ACCESS - 从来没有在设备上出现问题.

在另一个地方,我使用自己的完成块实现来在用户解除模态视图后采取行动.

    ValuePickerController *controller = 
    [[ValuePickerController alloc] 
        initWithNibName: kValuePickerXIBFileName
        bundle: nil
        labelText: @"prompt")
        value: alertSettings.frequency
        minimumValue: kMinimumFrequency
        maximumValue: kMaximumFrequency
     completionBlock: ^(NSInteger newValue) {
         [self updateFrequencyText: newValue];
         [self changeFrequencySetting];
     }];
Run Code Online (Sandbox Code Playgroud)

没有NSZombies出现,分析仪运行干净.此外,此代码已生产6个月,没有崩溃.

还有其他人有这个麻烦吗?自从我升级XCode以来,它一直在发生.

Jim*_*vey 22

据我所知,这是一个已知问题,只影响4.3模拟器.4.2和预发行版5.0版本似乎没有出现此问题.然而,现在狮子已经出了问题,因为Xcode的最新通用版本只支持4.3模拟器,出现这个问题.

实际原因是Block和ObjC运行时之间的钩子.块本身也可以正常工作,但任何在它们上调用Objective-C消息的尝试都会导致段错误.这是因为Blocks运行时包含对相关ObjC类的几个未初始化的引用,并且在iOS 4.3模拟器上,当ObjC运行时加载时它们从未被初始化(它们仅在ObjC被使用时才被初始化 - 所以Blocks运行时不依赖于加载Foundation.您可以通过查看值在运行时检查这个_NSConcreteStackBlock,_NSConcreteGlobalBlock并且_NSConcreteMallocBlock在调试器.在4.2模拟器或设备上,这些值将是非零的,但在4.3模拟器上它们仍为零.

我有一个潜在的解决方案,如果有必要,我将链接到这里,但首先我要尝试从Apple获取一些信息,以确定他们是否已经修复了发布的尖端,或者他们是否需要更多信息等等.

更新:解决问题

我做了很多挖掘,最终归结为:不要使用libSystem.dylib进行弱连接-weak_library.相反,你应该根本不弱连接libSystem(我不得不支持iOS 3.1.x,因为在某些特定于iOS4的条件代码中编译器生成的Blocks代码在启动时导致链接错误,即坏的崩溃),或者你应该使用-weak lSystem,而模拟器更好地理解.

当您在iOS模拟器中运行时,您可以查看加载的库(在Xcode:'Product-> Debug-> Shared Libraries ...'),如果您搜索'Blocks',您将看到两个项目:libsystem_blocks.dyliblibsystem_sim_blocks.dylib.后者是由CoreFoundation链接的,它为Blocks运行时初始化ObjC运行时粘合剂.但是,由于您将libSystem库作为一个整体进行弱连接,因此通常由Simulator版本覆盖的符号(因为它比libSystem更晚加载)实际上是在运行时从实现它们的第一个库中覆盖的.这意味着您将找到系统版本_NSConcreteGlobalBlock和朋友,这些版本不是由Simulator的自定义ObjC运行时初始化的版本.

对于(很多!)有关该问题的更多信息,以及如何跟踪它,请查看我在Apple Developer论坛上创建的主题.

  • 感谢你挖掘它,这已经困扰了我们一段时间,现在已经成为必不可少的,因为最新版本的Xcode没有4.3模拟器,这也打破了5.0模拟器.简单地说,需要做的是:1.在项目构建设置编辑器的"链接"标题下,查找"其他链接器标志".它将包含`-weak_library`,`-all_load`,`-ObjC`的条目.3.单击`-weak_library`的条目,然后用`-weak-lSystem`替换**.瞧瞧! (6认同)