objective-c - 在 iPhone Simulator 4.3/XCode 4.2 和 4.0.2 中使用 Blocks 会导致应用程序崩溃

标签 objective-c ios xcode ios-simulator objective-c-blocks

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

我的代码长期有效、经过测试并且在生产中使用 block 来指定完成操作。例如,我使用 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];
                 }];

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

在另一个地方,我使用自己的完成 block 实现在用户关闭模态视图后采取行动。

    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 个月,没有发生任何崩溃。

还有其他人遇到这个问题吗?自从我升级 XCode 以来,它一直在发生。

最佳答案

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

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

我有一个可能的解决方案,如有必要,我会链接到这里,但首先我会尝试从 Apple 那里获取一些信息,了解他们是否已在发布的风口浪尖上进行修复,或者他们是否需要更多信息信息等

更新:问题已解决

我进行了大量挖掘,最终归结为:不要使用 -weak_library 对 libSystem.dylib 进行弱链接。相反,您根本不应该弱链接 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 库作为一个整体进行弱链接,因此通常被模拟器版本覆盖的符号(因为它加载晚于 libSystem)实际上在运行时从 第一个 实现它们的库。这意味着您会找到 _NSConcreteGlobalBlock 和 friend 的系统版本,它们不是由模拟器的自定义 ObjC 运行时初始化的版本。

有关该问题的(很多!)更多信息,并查看我是如何追踪到它的,请查看我创建的线程 on the Apple Developer Forums .

关于objective-c - 在 iPhone Simulator 4.3/XCode 4.2 和 4.0.2 中使用 Blocks 会导致应用程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6738858/

相关文章:

objective-c - 尝试更改背景颜色时不显示自定义 View

objective-c - 在ARC下,Objective-C的property和declare混淆了

ios - 检测 Sprite 之间的碰撞

ios - 滑动删除按钮位于自定义 UITableViewCell 文本下方

ios - 缓存图像和 UICollectionView

ios - 删除 'NSString' 中的后端字符

objective-c - 无法使用 Swift 将此 CGFloat 分配给 XCode 中的属性

ios - 如何将 UITapGestureRecognizer 添加到 TableView 单元格内的 UILabel?

ios - 如何组织tableview单元格

ios - "dyld: Library not loaded"错误