在后台线程上调用 AVFoundation 会干扰 SwiftUI 动画

问题描述 投票:0回答:1

我有一个带有动画卡顿的应用程序,我已将其提炼为以下复制品:

struct ContentView: View {
    var body: some View {
        ZStack {
            AnimatingCircle()
            Button("Trigger animation stutter") {
                Task {
                    await MyActor().go()
                }
            }
        }
    }
}

private struct AnimatingCircle: View {
    @State var shouldAnimate = false
    var body: some View {
        Circle()
            .fill(.red)
            .animation(.easeInOut.repeatForever(autoreverses: true)) {
                $0.scaleEffect(shouldAnimate ? 1.5 : 0.5)
            }
            .onAppear {
                shouldAnimate = true
            }
    }
}

final actor MyActor {
    let captureSession = AVCaptureSession()

    func go() {
        let microphone = AVCaptureDevice.DiscoverySession(
            deviceTypes: [.microphone],
            mediaType: .audio,
            position: .unspecified
        ).devices.first!
        captureSession.addInput(try! AVCaptureDeviceInput(device: microphone))
        captureSession.addOutput(AVCaptureAudioDataOutput())
        captureSession.startRunning()
    }
}

点击按钮时,圆圈动画中有非常明显的卡顿现象。我已经验证我所做的所有 AVFoundation 调用都在后台线程上。我不知道如何解决这个问题。

首先,AVFoundation 代码怎么可能干扰动画?这是否意味着 AVFoundation 工作中的某些内容正在分派回主线程?

第二,有什么解决这个问题的想法吗?

点击此处查看动画结果(动画很烦人):

更新1

我很欣赏对我使用任务和参与者的审查,但这不是原因。此代码也出现了相同的错误:

Button("Trigger animation stutter") {
    DispatchQueue.global().async {
        go()
    }
}

func go() {
    let captureSession = AVCaptureSession()
    let microphone = AVCaptureDevice.DiscoverySession(
        deviceTypes: [.microphone],
        mediaType: .audio,
        position: .unspecified
    ).devices.first!
    captureSession.addInput(try! AVCaptureDeviceInput(device: microphone))
    captureSession.addOutput(AVCaptureAudioDataOutput())
    captureSession.startRunning()
}
animation swiftui avfoundation actor
1个回答
0
投票
@State var capturing = false
…
Button("Capture") {
                capturing.toggle()
            }

.task(id: capturing) {
    if capturing == false {
        return
    }

    await go()
    capturing = false

}

nonisolated func go() async {

    let captureSession = AVCaptureSession()
        let microphone = AVCaptureDevice.DiscoverySession(
            deviceTypes: [.microphone],
            mediaType: .audio,
            position: .unspecified
        ).devices.first!
        captureSession.addInput(try! AVCaptureDeviceInput(device: microphone))
        captureSession.addOutput(AVCaptureAudioDataOutput())
        captureSession.startRunning()
    }
    try? await Task.sleep(forever) // up to you max time
}
© www.soinside.com 2019 - 2024. All rights reserved.