ARKit UIView setAnimationsEnabled вызывается из фонового потока - PullRequest
1 голос
/ 19 февраля 2020

У меня есть приложение ARKit, которое отображает изображения. Они работают нормально, но если я пытаюсь использовать этот код для отображения анимированных GIF-файлов, я получаю следующие ошибки (при необходимости возможна полная трассировка стека).

[Animation] +[UIView setAnimationsEnabled:] being called from a background thread. Performing any operation from a background thread on UIView or a subclass is not supported and may result in unexpected and insidious behavior. trace=(
    0   UIKitCore                           0x0000000191b6cb1c D7630067-7A00-3CB7-99E1-E7F6C55D85C5 + 15252252
    1   libdispatch.dylib                   0x0000000102ddabd8 _dispatch_client_callout + 16
    2   libdispatch.dylib                   0x0000000102ddc4c8 _dispatch_once_callout + 84
    3   UIKitCore                           0x0000000191b6ca80 D7630067-7A00-3CB7-99E1-E7F6C55D85C5 + 15252096
    4   UIKitCore                           0x0000000191b6cc08 D7630067-7A00-3CB7-99E1-E7F6C55D85C5 + 15252488
...

Я не могу найти нигде, где код выбирает запуск в фоновом потоке. В моем коде addImage() работает нормально, но addGIF() вызывает ошибку выше. Соответствующие части моего ViewController.swift:

import UIKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var planeDetected: UILabel!
    @IBOutlet weak var sceneView: ARSCNView!

    let configuration = ARWorldTrackingConfiguration()
    var portalDisplayed = false

    override func viewDidLoad() {
        super.viewDidLoad()
        self.sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
        self.configuration.planeDetection = .horizontal
        self.sceneView.session.run(configuration)
        self.sceneView.delegate = self
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        self.sceneView.addGestureRecognizer(tapGestureRecognizer)
    }

    @objc func handleTap(sender: UITapGestureRecognizer) {
        guard let sceneView = sender.view as? ARSCNView else {return}
        let touchLocation = sender.location(in: sceneView)
        let hitTestResult = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
        if !hitTestResult.isEmpty {
            self.addPortal(hitTestResult: hitTestResult.first!)
        } else {
            //
        }
    }

    func addPortal(hitTestResult: ARHitTestResult) {
        self.portalDisplayed = true
        self.sceneView.debugOptions = []
        let portalScene = SCNScene(named: "Portal.scnassets/Portal.scn")
        let portalNode = portalScene!.rootNode.childNode(withName: "Portal", recursively: false)!
        let transform = hitTestResult.worldTransform
        let planeXposition = transform.columns.3.x
        let planeYposition = transform.columns.3.y
        let planeZposition = transform.columns.3.z
        portalNode.position = SCNVector3(planeXposition, planeYposition, planeZposition)
        self.sceneView.scene.rootNode.addChildNode(portalNode)

        ...

        // Using the commented line below instead means I don't get this error!
        // self.addImage(nodeName: "box", portalNode: portalNode, imageName: "image")
        self.addGIF(nodeName: "box", portalNode: portalNode, imageName: "image")
    }

    func addImage(nodeName: String, portalNode: SCNNode, imageName: String) {
        let child = portalNode.childNode(withName: nodeName, recursively: true)
        child?.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "Portal.scnassets/\(imageName).jpg")
        child?.renderingOrder = 300
    }

    func addGIF(nodeName: String, portalNode: SCNNode, imageName: String) {
        let child = portalNode.childNode(withName: nodeName, recursively: true)
        let gifImage = UIImage.gifImageWithName("\(imageName)")
        let gifImageView = UIImageView(image: gifImage)
        child?.geometry?.firstMaterial?.diffuse.contents = gifImageView
    }

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard anchor is ARPlaneAnchor else {return}
        DispatchQueue.main.async {
            if self.portalDisplayed == false {
                self.planeDetected.isHidden = false
            }
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            self.planeDetected.isHidden = true
        }
    }

}

Есть ли способ предотвратить это при вызове кода по ссылке выше? Я также попробовал следующее, но я все еще получаю ту же ошибку:

        DispatchQueue.main.async {
            self.addGIF(nodeName: "boxBW", portalNode: portalNode, imageName: "angel")
        }

Я проверил ряд поднятых проблем (таких как this ), но они не делают кажется, что отвечают на этот конкретный c вопрос.

...