在iPhone模拟器4.3/XCode 4.2和4.0.2中使用block导致应用程序崩溃



还有谁在XCode 4.2(lion)或4.0.2中遇到4.3 iPhone模拟器的问题吗?

我的代码已经工作了很长时间,经过测试,并在生产中使用块来指定完成动作。例如,我使用UIView animate来淡出标签顶部的一些文本,如下所示:

[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];
                 }];

我在模拟器中可靠地获得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];
     }];

没有NSZombies出现,并且分析器运行干净。此外,这段代码已经投入生产6个月了,没有出现任何崩溃。

还有谁遇到这种麻烦吗?

据我所知,这是一个已知的问题,只影响4.3模拟器。4.2和预发布5.0版本似乎没有出现此问题。但是现在Lion已经发布了,这个问题就更严重了,因为Xcode的最新通用版本只支持4.3模拟器,所以出现了这个问题。

实际原因在于block和ObjC运行时之间的钩子。块本身将工作得很好,但任何试图在它们上调用Objective-C消息的尝试都会导致段错误。这是因为Blocks运行时包含对相关ObjC类的未初始化引用,并且在iOS 4.3模拟器上,当ObjC运行时加载时,这些引用从未被初始化(它们只有在使用ObjC时才被初始化——因此Blocks运行时不依赖于加载Foundation)。您可以在运行时通过查看调试器中_NSConcreteStackBlock_NSConcreteGlobalBlock_NSConcreteMallocBlock的值来检查这一点。在4.2模拟器或设备上,这些值将是非空值,但在4.3模拟器上它们仍然为零。

我有一个可能的解决方案,如果有必要我会链接到这里,但首先我要尝试&从苹果那里挤出一些信息,比如他们是否在发布前夕有了解决方案,或者他们是否需要更多的信息,等等。

UPDATE: PROBLEM SOLVED

我做了很多挖掘,最终归结为:不要弱链接libSystem。使用-weak_library 。相反,你应该完全不要弱链接libSystem(我在支持iOS 3.1时必须这样做)。x,因为编译器生成的block代码在某些ios4特定的条件代码中会在启动时导致链接错误(即严重的崩溃),或者你应该使用-weak lSystem代替,模拟器可以更好地理解。

当你在iOS模拟器中运行时,你可以查看加载的库(在Xcode中:'Product->Debug->Shared libraries…'),如果你搜索'Blocks',你会看到两个项目:libsystem_blocks.dyliblibsystem_sim_blocks.dylib。后者是由CoreFoundation链接的,它为Blocks运行时初始化ObjC运行时胶水。然而,由于您将libSystem库作为一个整体弱链接,通常由模拟器版本覆盖的符号(因为它加载晚于libSystem)实际上在运行时从实现它们的第一个库覆盖。这意味着您将找到_NSConcreteGlobalBlock和friends的系统版本,它们不是由模拟器的自定义ObjC运行时初始化的

关于这个问题的更多信息,以及我是如何找到它的,请查看我在苹果开发者论坛上的帖子

最新更新