You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何消除AVAssetExportSession导出时的主线程隔离数据竞争警告?

消除AVAssetExportSession导出时的Sendable警告

你遇到的警告是因为AVAssetExportSession并非Sendable类型,在非主actor隔离的上下文里传递这类对象可能引发数据竞争——AVFoundation的多数API设计为在主队列/主actor环境下使用。以下是两种可行的解决方式:

方式一:仅将导出相关操作限定在主actor执行

把涉及exportSession的设置、导出调用及状态检查逻辑,用MainActor.run包裹,确保这部分代码在主actor上下文运行:

func extractAudioFromImportedVideo(videoURL: URL, success: @escaping ((URL) -> Void), failure: @escaping ((Error?) -> Void)) async {
        
    do {
        let asset = AVURLAsset(url: videoURL)
        let audioTracks = try await asset.loadTracks(withMediaType: .audio)
        
        guard !audioTracks.isEmpty else {
            failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Video does not contain audio"]))
            return
        }
        
        guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
            failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create export session"]))
            return
        }
        
        guard let audioURL = makeFileOutputURL(fileName: "ExtractedAudio.m4a") else {
            failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create output URL"]))
            return
        }
        
        print("audioTracks", audioTracks)
        
        // 用MainActor.run包裹导出相关逻辑
        await MainActor.run {
            exportSession.outputURL = audioURL
            exportSession.outputFileType = .m4a
            
            await exportSession.export()
            print("exportSession.status", exportSession.status.rawValue)
            if exportSession.status == .completed {
                print("Audio extraction succeeded")
                success(audioURL)
            } else {
                print("Audio extraction failed: \(exportSession.error?.localizedDescription ?? "")")
                failure(exportSession.error)
            }
        }
    }
    catch {
        print("extractAudioFromImportedVideo Error:", error.localizedDescription)
    }
}

这种方式的优势是仅将必要的UI/AVFoundation相关操作放在主actor,避免阻塞主队列处理其他耗时任务(比如asset.loadTracks这类异步加载操作仍可在后台执行)。

方式二:将整个函数标记为主actor隔离

如果函数内所有操作都适合在主actor执行(比如没有大量后台耗时任务),可以直接给函数添加@MainActor标记:

@MainActor
func extractAudioFromImportedVideo(videoURL: URL, success: @escaping ((URL) -> Void), failure: @escaping ((Error?) -> Void)) async {
    // 原代码内容保持不变
}

这样整个函数的所有逻辑都会在主actor上下文运行,自然消除跨actor传递非Sendable对象的警告。

内容的提问来源于stack exchange,提问作者Hassan Taleb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 09:05:56