UIView animateWithDuration 使应用程序在从 dispatch_async 块调用时挂起

UIView animateWithDuration makes app hang when called from dispatch_async block

首先,我有一个如下所示的协议:

@protocol CryptoDelegate <NSObject>
- (void)cryptoManagerFinishedEncryption;
@end

有一个名为 CryptoManager 的单例,具有以下功能:

- (void)startEncryption:(NSURL *)path withDelegate:(id<CryptoDelegate>)delegate {
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // ... some stuff is happening here
        [delegate cryptoManagerFinishedEncryption];
    });
}

然后我有一个自制的MultiPopup可以显示面板(它必须扩展MultiPopupPanel来存储i.a。一个指向弹出窗口本身的指针)并在这些面板之间切换使用以下代码:

- (void)switchTo:(MultiPopupPanel*)panel {
    if(self.currentPanel != panel) {
        MultiPopupPanel* oldPanel = self.currentPanel;
        self.currentPanel = panel;
        self.currentPanel.alpha = 0;
        self.currentPanel.hidden = NO;

        if(oldPanel) {
            NSLog(@"Before animation");
            [UIView animateWithDuration:0.2f animations:^{
                oldPanel.alpha = 0;
            } completion:^(BOOL finished) {
                NSLog(@"After animation");
                oldPanel.hidden = YES;
                [UIView animateWithDuration:0.2f animations:^{
                    self.currentPanel.alpha = 1;
                }];
            }];
        } else {
            [UIView animateWithDuration:0.2f animations:^{
                self.currentPanel.alpha = 1;
            }];
        }
    }
}

现在我有一个扩展 MultiPopupPanel 并实现协议 CryptoDelegate 的面板。在它的 cryptoManagerFinishedEncryption 实现中,我正在调用我的 switchTo 函数,然后它应该切换到另一个面板。

这是应用程序挂起的地方:立即输出消息 "Before animation"。然后应用挂起 15-20 秒,然后出现动画,输出 "After animation" 消息并显示新面板。

只有当我在另一个线程(通过 dispatch_async)中使用 +[UIView animateWithDuration...] 时才会发生这种情况。如果我在没有 dispatch_async 的情况下调用委托(= 在主线程中),一切正常。

为什么会这样?是否允许从异步块调用动画?非常感谢任何帮助。

任何对 GUI 元素(例如动画、大小和内容)的更改都应该在主线程中进行,否则会产生奇怪的效果。

您必须始终在主线程上调用 UI 相关代码。不这样做是被禁止的,并且会导致意想不到的结果(通常是例外)。

当调用你的委托方法时,你应该再次使用 dispatch_asyncdispatch_get_main_queue,这样委托代码将 运行 在主线程上,你可以更新你的 UI.

另请参阅 these Apple docs 了解更多具体信息。