UIView.animate 未在 PHPhotoLibrary.shared().performChanges 中执行

UIView.animate not executed in PHPhotoLibrary.shared().performChanges

我一整天都在处理以下代码,但根本找不到问题所在。我想保存视频并在完成后使某些按钮或微调器(消失)出现。所有按钮都在 viewDidLoad 中设置,可以说是存在的(它们是可选的,因此也是可选的链接)。我的问题是 if 子句中的动画永远不会执行。只是有时如果我在每一行代码之前放置断点,它就会起作用,这真的让我感到奇怪(顺便说一句:断点并不表示任何异常)。此外,如果我将 if success2 == true 的代码替换为 else (if success2 == false) 的代码,它会起作用(在弹出警报后)。我几乎四次检查了我的代码,但就是找不到我做错了什么。有没有人知道问题可能是什么以及如何解决?

对于巨大的代码块感到抱歉:

PHPhotoLibrary.shared().performChanges({
    if let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url) {
        let assetCollectionChangeRequest = PHAssetCollectionChangeRequest(for: albumAssetCollection)
        let enumeration: NSArray = [assetChangeRequest.placeholderForCreatedAsset!]
        assetCollectionChangeRequest?.addAssets(enumeration)
    }
}, completionHandler: { (success2: Bool, error2: Error?) in
    if success2 == true {
        // prompt that the video has been saved
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
            if let checkButton = self.checkButton, let saveSpinner = self.saveSpinner, let resetButton = self.resetButton {
                saveSpinner.alpha = 0
                checkButton.alpha = 1
                resetButton.alpha = 1
            }
        }) { (completed: Bool) in
            if completed == true {
                if let saveSpinner = self.saveSpinner {
                    saveSpinner.stopAnimating()
                    self.timeLimitReached = false
                    self.changeClipsCount()
                }
                UIView.animate(withDuration: 0.5, delay: 3, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
                    if let checkButton = self.checkButton, let saveButton = self.saveButton {
                        checkButton.alpha = 0
                        saveButton.alpha = 1
                    }
                }) { (completed: Bool) in }
            }
        }
    } else {
        // prompt that the video has not been saved
        let alertController = UIAlertController(title: "Something failed!", message: "The video could not be saved.", preferredStyle: .alert)
        let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
        alertController.addAction(okAction)
        self.present(alertController, animated: true, completion: {
            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
                if let saveButton = self.saveButton, let saveSpinner = self.saveSpinner {
                    saveButton.alpha = 1
                    saveSpinner.alpha = 0
                }
            }) { (completed: Bool) in
                if let saveSpinner = self.saveSpinner {
                    saveSpinner.stopAnimating()
                    self.timeLimitReached = false
                }
            }
        })
    }
})

我会 post 我的评论作为一个更好的解释的答案。

要使 UIView 动画正常工作,它们必须在主线程上使用(就像所有其他 UIKit 东西一样!)。

From the documentation 对于 PHPhotoLibrary,Apple 声明:

Photos executes both the change block and the completion handler block on an arbitrary serial queue. To update your app’s UI as a result of a change, dispatch that work to the main queue.

这意味着您应该期望处理来自 Apple 的响应,就像它来自主线程以外的其他地方一样。因此,一个简单的解决方法是调用:

DispatchQueue.main.async {} 并将其包裹在您要执行 UIKit 内容的代码周围。

Apple 不在主线程上工作的原因是因为他们正在做的工作可能很重要,而且它会占用主线程,这会使您的 UI 迟钝和无响应.

我还建议对您的代码进行一些小调整,以使其更易于阅读。在完成处理程序中,我会将代码提取到一个函数中,然后您所要做的就是将该函数调用包装在一个 DispatchQueue.main.async {} 调用中,而不是将您想要设置动画的整个代码块包装起来。

另外不要忘记使用 Swift 的最佳语言功能之一:optional chaining。这意味着你不必在尝试使用它之前检查它是否存在,如果它不存在它就会退出。所以你可以安全地做这样的事情:

checkButton?.alpha = 1